chat_manager 1.1.0 → 1.2.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/CHANGELOG.md +21 -0
- data/README.md +2 -2
- data/app/assets/stylesheets/chat_manager/chat.css +194 -69
- data/app/views/chat_manager/_chat_card.html.erb +37 -15
- data/app/views/chat_manager/_chat_list.html.erb +44 -12
- data/lib/chat_manager/csv_downloadable.rb +6 -5
- data/lib/chat_manager/helpers.rb +14 -2
- data/lib/chat_manager/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: 700671f665ef55917beb61c67fb22c09b9532d61047ca0749833865548a1da0c
|
|
4
|
+
data.tar.gz: 18f1238d5225620129679a8457577f834da9412697d7451e3c61f0ffda50b27d
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: de96e54320b00a6d9347fe95a3d33c2fb8bebe50e66b0caace50902746467cf4004e11b1e76a935b221e2d5ccfdd536f73726a8ed8278509be175b5051c73d02
|
|
7
|
+
data.tar.gz: df7ef5b1082544b71b5232954a1ed5e98237d7517ac994542156612cfe8aaf04fc4940f9912d7043eb75af8aeb77d73f08f6fcf9e77c5987d72eedc3385ad10d
|
data/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,27 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/).
|
|
7
7
|
|
|
8
|
+
## [1.2.0] - 2026-06-04
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- Gmail-style multi-select on the chat list — checkbox per card, a kebab menu (delete selected, export selected) on the list toolbar, and a "select all visible" affordance. Selection state lives in a Stimulus controller; the host still owns the destroy / export routes.
|
|
13
|
+
|
|
14
|
+
### Changed
|
|
15
|
+
|
|
16
|
+
- Chat-list toolbar is now sticky and visually covers the host sidebar's top padding so chats scroll under it cleanly.
|
|
17
|
+
|
|
18
|
+
### Tested
|
|
19
|
+
|
|
20
|
+
- `ChatManager::CsvDownloadable#generate_csv_for_chats` role routing + interleaving of user / assistant rows.
|
|
21
|
+
- `ChatManager::TitleGeneratable` short-circuit when `title` is already set, 255-char truncation, and rescue behavior on `StandardError`.
|
|
22
|
+
|
|
23
|
+
## [1.1.1] - 2026-05-11
|
|
24
|
+
|
|
25
|
+
### Fixed
|
|
26
|
+
|
|
27
|
+
- `ChatManager::CsvDownloadable` referenced the old `prompt_manager_prompt_execution` association name, raising `ActiveRecord::AssociationNotFoundError` when host apps had migrated to `prompt_navigator`. The concern (and README/CLAUDE.md docs) now use `prompt_navigator_prompt_execution`.
|
|
28
|
+
|
|
8
29
|
## [1.1.0] - 2026-04-22
|
|
9
30
|
|
|
10
31
|
### Added
|
data/README.md
CHANGED
|
@@ -110,9 +110,9 @@ CSV output includes the following columns: `Chat Title`, `Role`, `Message Conten
|
|
|
110
110
|
**Prerequisites:** The host application must provide:
|
|
111
111
|
|
|
112
112
|
- `current_user` method in the controller (returning an object with a `chats` association)
|
|
113
|
-
- `chats` association that supports `.includes(messages: :
|
|
113
|
+
- `chats` association that supports `.includes(messages: :prompt_navigator_prompt_execution)`
|
|
114
114
|
- `ordered_messages` method on the Chat model
|
|
115
|
-
- Each message must have a `role` attribute and a `
|
|
115
|
+
- Each message must have a `role` attribute and a `prompt_navigator_prompt_execution` association with `prompt` and `response` attributes
|
|
116
116
|
|
|
117
117
|
### TitleGeneratable (Model Concern)
|
|
118
118
|
|
|
@@ -2,40 +2,39 @@
|
|
|
2
2
|
position: relative;
|
|
3
3
|
display: flex;
|
|
4
4
|
flex-direction: column;
|
|
5
|
-
gap:
|
|
6
|
-
padding-left: 32px; /* space for arrows */
|
|
5
|
+
gap: 2px;
|
|
7
6
|
}
|
|
8
7
|
|
|
9
8
|
.chat-card {
|
|
10
|
-
background:
|
|
11
|
-
border:
|
|
12
|
-
border-radius:
|
|
13
|
-
padding:
|
|
14
|
-
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.06);
|
|
9
|
+
background: transparent;
|
|
10
|
+
border: none;
|
|
11
|
+
border-radius: 6px;
|
|
12
|
+
padding: 4px 6px;
|
|
15
13
|
position: relative;
|
|
16
|
-
|
|
17
|
-
transition:
|
|
18
|
-
box-shadow 0.15s ease,
|
|
19
|
-
transform 0.15s ease;
|
|
14
|
+
transition: background-color 0.15s ease;
|
|
20
15
|
|
|
21
16
|
&.is-active {
|
|
22
|
-
|
|
23
|
-
box-shadow: 0 0 0 2px rgba(0, 123, 255, 0.25);
|
|
17
|
+
background-color: rgba(0, 123, 255, 0.10);
|
|
24
18
|
}
|
|
25
19
|
|
|
26
20
|
&:hover {
|
|
27
|
-
|
|
28
|
-
|
|
21
|
+
background-color: rgba(0, 0, 0, 0.05);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
&.is-active:hover {
|
|
25
|
+
background-color: rgba(0, 123, 255, 0.14);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
&.is-selected {
|
|
29
|
+
background-color: #eef5ff;
|
|
29
30
|
}
|
|
30
31
|
}
|
|
31
32
|
|
|
32
33
|
.chat-card-link {
|
|
33
|
-
display:
|
|
34
|
-
grid-template-columns: auto 1fr auto;
|
|
35
|
-
grid-gap: 8px;
|
|
34
|
+
display: block;
|
|
36
35
|
text-decoration: none;
|
|
37
|
-
color: #
|
|
38
|
-
|
|
36
|
+
color: #222;
|
|
37
|
+
min-width: 0;
|
|
39
38
|
}
|
|
40
39
|
|
|
41
40
|
.chat-card-number {
|
|
@@ -45,18 +44,20 @@
|
|
|
45
44
|
}
|
|
46
45
|
|
|
47
46
|
.chat-card-prompt {
|
|
48
|
-
font-size:
|
|
49
|
-
line-height: 1.
|
|
47
|
+
font-size: 13px;
|
|
48
|
+
line-height: 1.35;
|
|
50
49
|
overflow: hidden;
|
|
51
50
|
display: -webkit-box;
|
|
52
|
-
-webkit-line-clamp:
|
|
51
|
+
-webkit-line-clamp: 1;
|
|
53
52
|
-webkit-box-orient: vertical;
|
|
53
|
+
white-space: nowrap;
|
|
54
|
+
text-overflow: ellipsis;
|
|
54
55
|
}
|
|
55
56
|
|
|
56
57
|
.chat-card-row {
|
|
57
58
|
display: flex;
|
|
58
59
|
align-items: center;
|
|
59
|
-
gap:
|
|
60
|
+
gap: 6px;
|
|
60
61
|
}
|
|
61
62
|
|
|
62
63
|
.chat-card-row .chat-card-link {
|
|
@@ -64,90 +65,214 @@
|
|
|
64
65
|
min-width: 0;
|
|
65
66
|
}
|
|
66
67
|
|
|
67
|
-
.chat-card-
|
|
68
|
+
.chat-card-menu-wrap {
|
|
69
|
+
position: relative;
|
|
70
|
+
flex-shrink: 0;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
.chat-card-menu-btn {
|
|
68
74
|
display: flex;
|
|
69
75
|
align-items: center;
|
|
70
76
|
justify-content: center;
|
|
71
|
-
width:
|
|
72
|
-
height:
|
|
77
|
+
width: 22px;
|
|
78
|
+
height: 22px;
|
|
79
|
+
padding: 0;
|
|
80
|
+
border: none;
|
|
81
|
+
background: transparent;
|
|
73
82
|
border-radius: 4px;
|
|
74
|
-
color: #
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
transition: color 0.15s ease, background-color 0.15s ease;
|
|
83
|
+
color: #777;
|
|
84
|
+
cursor: pointer;
|
|
85
|
+
opacity: 0;
|
|
86
|
+
transition: opacity 0.15s ease, color 0.15s ease, background-color 0.15s ease;
|
|
87
|
+
|
|
88
|
+
i {
|
|
89
|
+
font-size: 14px;
|
|
90
|
+
}
|
|
78
91
|
|
|
79
92
|
&:hover {
|
|
80
|
-
color: #
|
|
81
|
-
background-color: rgba(0,
|
|
93
|
+
color: #222;
|
|
94
|
+
background-color: rgba(0, 0, 0, 0.08);
|
|
82
95
|
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
.chat-card:hover .chat-card-menu-btn,
|
|
99
|
+
.chat-card-menu-wrap:has(.chat-card-menu.open) .chat-card-menu-btn {
|
|
100
|
+
opacity: 1;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
.chat-card-menu {
|
|
104
|
+
position: absolute;
|
|
105
|
+
top: 100%;
|
|
106
|
+
right: 0;
|
|
107
|
+
margin-top: 4px;
|
|
108
|
+
min-width: 160px;
|
|
109
|
+
background: #fff;
|
|
110
|
+
border: 1px solid #e5e7eb;
|
|
111
|
+
border-radius: 6px;
|
|
112
|
+
box-shadow: 0 6px 16px rgba(0, 0, 0, 0.12);
|
|
113
|
+
padding: 4px;
|
|
114
|
+
z-index: 20;
|
|
115
|
+
display: none;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
.chat-card-menu.open {
|
|
119
|
+
display: flex;
|
|
120
|
+
flex-direction: column;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
.chat-card-menu-item {
|
|
124
|
+
display: flex;
|
|
125
|
+
align-items: center;
|
|
126
|
+
gap: 8px;
|
|
127
|
+
padding: 6px 8px;
|
|
128
|
+
font-size: 12px;
|
|
129
|
+
color: #333;
|
|
130
|
+
text-decoration: none;
|
|
131
|
+
border-radius: 4px;
|
|
132
|
+
border: none;
|
|
133
|
+
background: transparent;
|
|
134
|
+
cursor: pointer;
|
|
135
|
+
text-align: left;
|
|
136
|
+
width: 100%;
|
|
137
|
+
box-sizing: border-box;
|
|
83
138
|
|
|
84
139
|
i {
|
|
85
140
|
font-size: 12px;
|
|
86
141
|
}
|
|
142
|
+
|
|
143
|
+
&:hover {
|
|
144
|
+
background-color: #f3f4f6;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
.chat-card-menu-item-danger {
|
|
149
|
+
color: #dc2626;
|
|
150
|
+
|
|
151
|
+
&:hover {
|
|
152
|
+
background-color: rgba(220, 38, 38, 0.08);
|
|
153
|
+
}
|
|
87
154
|
}
|
|
88
155
|
|
|
89
|
-
.chat-card-
|
|
156
|
+
.chat-card-menu-form {
|
|
90
157
|
margin: 0;
|
|
158
|
+
width: 100%;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
.chat-list-toolbar {
|
|
162
|
+
display: flex;
|
|
163
|
+
align-items: center;
|
|
164
|
+
gap: 8px;
|
|
165
|
+
min-height: 28px;
|
|
166
|
+
/* Pin the heading + bulk-action row to the top of the scrollable
|
|
167
|
+
sidebar so it stays accessible when the chat list is long. The
|
|
168
|
+
opaque background masks cards scrolling underneath; the explicit
|
|
169
|
+
z-index lifts the toolbar above sibling cards in stacking. The
|
|
170
|
+
negative top/side margins extend the toolbar across the host
|
|
171
|
+
sidebar's 8px padding so scrolling cards can't peek through the
|
|
172
|
+
gap above it; equal padding keeps the toolbar's content in its
|
|
173
|
+
natural place. */
|
|
174
|
+
position: sticky;
|
|
175
|
+
top: 0;
|
|
176
|
+
background-color: #ffffff;
|
|
177
|
+
z-index: 2;
|
|
178
|
+
margin: -8px -8px 6px;
|
|
179
|
+
padding: 8px 8px 0;
|
|
180
|
+
|
|
181
|
+
h2 {
|
|
182
|
+
margin: 0;
|
|
183
|
+
font-size: 14px;
|
|
184
|
+
line-height: 1.2;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
.chat-list-select-all {
|
|
189
|
+
width: 16px;
|
|
190
|
+
height: 16px;
|
|
191
|
+
margin: 0;
|
|
192
|
+
cursor: pointer;
|
|
193
|
+
accent-color: #007bff;
|
|
194
|
+
flex-shrink: 0;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
.chat-list-heading {
|
|
198
|
+
flex: 1;
|
|
199
|
+
min-width: 0;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
.chat-list-bar {
|
|
203
|
+
flex: 1;
|
|
204
|
+
display: flex;
|
|
205
|
+
align-items: center;
|
|
206
|
+
justify-content: space-between;
|
|
207
|
+
gap: 8px;
|
|
208
|
+
min-width: 0;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
.chat-list-toolbar .hidden {
|
|
212
|
+
display: none;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
.chat-list-bar-count {
|
|
216
|
+
font-size: 12px;
|
|
217
|
+
color: #555;
|
|
218
|
+
white-space: nowrap;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
.chat-list-bar-actions {
|
|
91
222
|
display: flex;
|
|
92
223
|
align-items: center;
|
|
224
|
+
gap: 4px;
|
|
93
225
|
}
|
|
94
226
|
|
|
95
|
-
.chat-
|
|
227
|
+
.chat-list-bar-download,
|
|
228
|
+
.chat-list-bar-delete {
|
|
96
229
|
display: flex;
|
|
97
230
|
align-items: center;
|
|
98
231
|
justify-content: center;
|
|
99
|
-
width:
|
|
100
|
-
height:
|
|
232
|
+
width: 28px;
|
|
233
|
+
height: 28px;
|
|
101
234
|
padding: 0;
|
|
102
235
|
border: none;
|
|
103
236
|
background: transparent;
|
|
104
237
|
border-radius: 4px;
|
|
105
|
-
color: #888;
|
|
106
238
|
cursor: pointer;
|
|
107
|
-
|
|
239
|
+
color: #555;
|
|
108
240
|
transition: color 0.15s ease, background-color 0.15s ease;
|
|
109
241
|
|
|
110
|
-
&:hover {
|
|
111
|
-
color: #dc2626;
|
|
112
|
-
background-color: rgba(220, 38, 38, 0.1);
|
|
113
|
-
}
|
|
114
|
-
|
|
115
242
|
i {
|
|
116
|
-
font-size:
|
|
243
|
+
font-size: 14px;
|
|
117
244
|
}
|
|
118
245
|
}
|
|
119
246
|
|
|
120
|
-
.chat-download
|
|
121
|
-
|
|
122
|
-
|
|
247
|
+
.chat-list-bar-download:hover {
|
|
248
|
+
color: #007bff;
|
|
249
|
+
background-color: rgba(0, 123, 255, 0.1);
|
|
123
250
|
}
|
|
124
251
|
|
|
125
|
-
.chat-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
font-size: 12px;
|
|
130
|
-
color: #555;
|
|
131
|
-
text-decoration: none;
|
|
132
|
-
padding: 6px 10px;
|
|
133
|
-
border: 1px solid #ddd;
|
|
134
|
-
border-radius: 6px;
|
|
135
|
-
transition: color 0.15s ease, border-color 0.15s ease, background-color 0.15s ease;
|
|
252
|
+
.chat-list-bar-delete:hover {
|
|
253
|
+
color: #dc2626;
|
|
254
|
+
background-color: rgba(220, 38, 38, 0.1);
|
|
255
|
+
}
|
|
136
256
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
257
|
+
.chat-card-checkbox {
|
|
258
|
+
width: 14px;
|
|
259
|
+
height: 14px;
|
|
260
|
+
margin: 0;
|
|
261
|
+
cursor: pointer;
|
|
262
|
+
accent-color: #007bff;
|
|
263
|
+
flex-shrink: 0;
|
|
264
|
+
opacity: 0;
|
|
265
|
+
transition: opacity 0.15s ease;
|
|
266
|
+
}
|
|
142
267
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
268
|
+
.chat-card:hover .chat-card-checkbox,
|
|
269
|
+
.chat-card-checkbox:checked {
|
|
270
|
+
opacity: 1;
|
|
146
271
|
}
|
|
147
272
|
|
|
148
273
|
.chat-card-title-input {
|
|
149
|
-
font-size:
|
|
150
|
-
line-height: 1.
|
|
274
|
+
font-size: 13px;
|
|
275
|
+
line-height: 1.35;
|
|
151
276
|
width: 100%;
|
|
152
277
|
padding: 2px 4px;
|
|
153
278
|
border: 1px solid #ccc;
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
card_path = locals[:card_path]
|
|
5
5
|
download_csv_path = locals[:download_csv_path]
|
|
6
6
|
delete_path = locals[:delete_path]
|
|
7
|
+
selectable = locals[:selectable]
|
|
7
8
|
%>
|
|
8
9
|
|
|
9
10
|
<div class="chat-card<%= ' is-active' if is_active %>"
|
|
@@ -14,24 +15,45 @@
|
|
|
14
15
|
data-chat-title-edit-full-title-value="<%= ann.title.to_s %>"
|
|
15
16
|
data-chat-title-edit-update-url-value="<%= main_app.update_title_chat_path(ann.uuid) %>">
|
|
16
17
|
<div class="chat-card-row">
|
|
18
|
+
<% if selectable %>
|
|
19
|
+
<input type="checkbox"
|
|
20
|
+
class="chat-card-checkbox"
|
|
21
|
+
data-chat-target="checkbox"
|
|
22
|
+
data-uuid="<%= ann.uuid %>"
|
|
23
|
+
data-action="click->chat#toggle" />
|
|
24
|
+
<% end %>
|
|
17
25
|
<%= link_to card_path.call(ann.uuid), class: "chat-card-link", data: { "chat-title-edit-target": "link" } do %>
|
|
18
26
|
<div class="chat-card-prompt" data-chat-title-edit-target="display"><%= truncate(ann.title.to_s, length: 30) %></div>
|
|
19
27
|
<% end %>
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
28
|
+
<div class="chat-card-menu-wrap" data-controller="chat-menu">
|
|
29
|
+
<button type="button"
|
|
30
|
+
class="chat-card-menu-btn"
|
|
31
|
+
title="More actions"
|
|
32
|
+
data-action="click->chat-menu#toggle">
|
|
33
|
+
<i class="bi bi-three-dots-vertical"></i>
|
|
34
|
+
</button>
|
|
35
|
+
<div class="chat-card-menu" data-chat-menu-target="menu">
|
|
36
|
+
<button type="button"
|
|
37
|
+
class="chat-card-menu-item"
|
|
38
|
+
data-action="click->chat-menu#close click->chat-title-edit#start">
|
|
39
|
+
<i class="bi bi-pencil"></i> Rename
|
|
40
|
+
</button>
|
|
41
|
+
<% if delete_path %>
|
|
42
|
+
<%= button_to delete_path.call(ann.uuid),
|
|
43
|
+
method: :delete,
|
|
44
|
+
class: "chat-card-menu-item chat-card-menu-item-danger",
|
|
45
|
+
form: { class: "chat-card-menu-form" },
|
|
46
|
+
data: { turbo_confirm: "Delete this chat? This cannot be undone." } do %>
|
|
47
|
+
<i class="bi bi-trash"></i> Delete
|
|
48
|
+
<% end %>
|
|
49
|
+
<% end %>
|
|
50
|
+
<% if download_csv_path %>
|
|
51
|
+
<%= link_to download_csv_path.call(ann.uuid), class: "chat-card-menu-item", data: { turbo: false } do %>
|
|
52
|
+
<i class="bi bi-download"></i> Download
|
|
53
|
+
<% end %>
|
|
54
|
+
<% end %>
|
|
55
|
+
</div>
|
|
56
|
+
</div>
|
|
35
57
|
</div>
|
|
36
58
|
<input type="text" class="chat-card-title-input"
|
|
37
59
|
data-chat-title-edit-target="input"
|
|
@@ -2,25 +2,57 @@
|
|
|
2
2
|
active_uuid = locals[:active_uuid]
|
|
3
3
|
card_path = locals[:card_path]
|
|
4
4
|
download_csv_path = locals[:download_csv_path]
|
|
5
|
-
download_all_csv_path = locals[:download_all_csv_path]
|
|
6
5
|
delete_path = locals[:delete_path]
|
|
7
|
-
|
|
6
|
+
batch_delete_path = locals[:batch_delete_path]
|
|
7
|
+
batch_download_csv_path = locals[:batch_download_csv_path]
|
|
8
|
+
titled_chats = @chats.select { |c| c.title.present? }.reverse
|
|
9
|
+
selectable = batch_delete_path.present? || batch_download_csv_path.present?
|
|
8
10
|
%>
|
|
9
11
|
|
|
10
|
-
<h2>chat</h2>
|
|
11
12
|
<% if titled_chats.present? %>
|
|
12
|
-
<div class="chat-stack"
|
|
13
|
+
<div class="chat-stack"
|
|
14
|
+
data-controller="chat"
|
|
15
|
+
data-chat-batch-delete-path-value="<%= batch_delete_path %>"
|
|
16
|
+
data-chat-batch-download-csv-path-value="<%= batch_download_csv_path %>">
|
|
17
|
+
<div class="chat-list-toolbar">
|
|
18
|
+
<div class="chat-list-heading" data-chat-target="heading">
|
|
19
|
+
<h2>Chats</h2>
|
|
20
|
+
</div>
|
|
21
|
+
<div class="chat-list-bar hidden" data-chat-target="bar">
|
|
22
|
+
<span class="chat-list-bar-count">
|
|
23
|
+
<span data-chat-target="selectedCount">0</span> selected
|
|
24
|
+
</span>
|
|
25
|
+
<div class="chat-list-bar-actions">
|
|
26
|
+
<% if batch_download_csv_path %>
|
|
27
|
+
<button type="button"
|
|
28
|
+
class="chat-list-bar-download"
|
|
29
|
+
title="Download selected as CSV"
|
|
30
|
+
data-action="click->chat#bulkDownload">
|
|
31
|
+
<i class="bi bi-download"></i>
|
|
32
|
+
</button>
|
|
33
|
+
<% end %>
|
|
34
|
+
<% if batch_delete_path %>
|
|
35
|
+
<button type="button"
|
|
36
|
+
class="chat-list-bar-delete"
|
|
37
|
+
title="Delete selected"
|
|
38
|
+
data-action="click->chat#bulkDelete">
|
|
39
|
+
<i class="bi bi-trash"></i>
|
|
40
|
+
</button>
|
|
41
|
+
<% end %>
|
|
42
|
+
</div>
|
|
43
|
+
</div>
|
|
44
|
+
<% if selectable %>
|
|
45
|
+
<input type="checkbox"
|
|
46
|
+
class="chat-list-select-all"
|
|
47
|
+
data-chat-target="selectAll"
|
|
48
|
+
data-action="change->chat#toggleAll"
|
|
49
|
+
title="Select all" />
|
|
50
|
+
<% end %>
|
|
51
|
+
</div>
|
|
13
52
|
<% titled_chats.each_with_index do |ann, idx| %>
|
|
14
|
-
<%= render 'chat_manager/chat_card', locals: { ann: ann, next_ann: titled_chats[idx + 1], is_active: ann.
|
|
53
|
+
<%= render 'chat_manager/chat_card', locals: { ann: ann, next_ann: titled_chats[idx + 1], is_active: ann.uuid == active_uuid, card_path: card_path, download_csv_path: download_csv_path, delete_path: delete_path, selectable: selectable } %>
|
|
15
54
|
<% end %>
|
|
16
55
|
</div>
|
|
17
|
-
<% if download_all_csv_path %>
|
|
18
|
-
<div class="chat-download-all">
|
|
19
|
-
<%= link_to download_all_csv_path, class: "chat-download-all-link", data: { turbo: false } do %>
|
|
20
|
-
<i class="bi bi-download"></i> Download All Chats CSV
|
|
21
|
-
<% end %>
|
|
22
|
-
</div>
|
|
23
|
-
<% end %>
|
|
24
56
|
<% else %>
|
|
25
57
|
<p class="chat-empty">No chat yet</p>
|
|
26
58
|
<% end %>
|
|
@@ -9,7 +9,7 @@ module ChatManager
|
|
|
9
9
|
CSV_HEADERS = [ "Chat Title", "Role", "Message Content", "Sent At", "Model" ].freeze
|
|
10
10
|
|
|
11
11
|
def download_csv
|
|
12
|
-
chat = current_user.chats.includes(messages: :
|
|
12
|
+
chat = current_user.chats.includes(messages: :prompt_navigator_prompt_execution).find_by!(uuid: params[:id])
|
|
13
13
|
|
|
14
14
|
csv_data = generate_csv_for_chats([ chat ])
|
|
15
15
|
|
|
@@ -17,12 +17,13 @@ module ChatManager
|
|
|
17
17
|
send_data csv_data, filename: filename, type: "text/csv"
|
|
18
18
|
end
|
|
19
19
|
|
|
20
|
-
def
|
|
21
|
-
|
|
20
|
+
def download_selected_csv
|
|
21
|
+
uuids = Array(params[:uuids]).reject(&:blank?)
|
|
22
|
+
chats = current_user.chats.where(uuid: uuids).includes(messages: :prompt_navigator_prompt_execution)
|
|
22
23
|
|
|
23
24
|
csv_data = generate_csv_for_chats(chats)
|
|
24
25
|
|
|
25
|
-
send_data csv_data, filename: "
|
|
26
|
+
send_data csv_data, filename: "chats_#{Date.today}.csv", type: "text/csv"
|
|
26
27
|
end
|
|
27
28
|
|
|
28
29
|
private
|
|
@@ -32,7 +33,7 @@ module ChatManager
|
|
|
32
33
|
csv << CSV_HEADERS
|
|
33
34
|
chats.each do |chat|
|
|
34
35
|
chat.ordered_messages.each do |msg|
|
|
35
|
-
pe = msg.
|
|
36
|
+
pe = msg.prompt_navigator_prompt_execution
|
|
36
37
|
content = msg.role == "user" ? pe&.prompt : pe&.response
|
|
37
38
|
csv << [ chat.title, msg.role, content, msg.created_at, chat.model ]
|
|
38
39
|
end
|
data/lib/chat_manager/helpers.rb
CHANGED
|
@@ -1,7 +1,19 @@
|
|
|
1
1
|
module ChatManager
|
|
2
2
|
module Helpers
|
|
3
|
-
def chat_list(card_path,
|
|
4
|
-
|
|
3
|
+
def chat_list(card_path,
|
|
4
|
+
active_uuid: nil,
|
|
5
|
+
download_csv_path: nil,
|
|
6
|
+
delete_path: nil,
|
|
7
|
+
batch_delete_path: nil,
|
|
8
|
+
batch_download_csv_path: nil)
|
|
9
|
+
render "chat_manager/chat_list", locals: {
|
|
10
|
+
card_path: card_path,
|
|
11
|
+
active_uuid: active_uuid,
|
|
12
|
+
download_csv_path: download_csv_path,
|
|
13
|
+
delete_path: delete_path,
|
|
14
|
+
batch_delete_path: batch_delete_path,
|
|
15
|
+
batch_download_csv_path: batch_download_csv_path
|
|
16
|
+
}
|
|
5
17
|
end
|
|
6
18
|
end
|
|
7
19
|
end
|
data/lib/chat_manager/version.rb
CHANGED