rio-assist-widget 0.1.6 → 0.1.7
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.
- package/dist/rio-assist.js +52 -36
- package/index.html +9 -17
- package/package.json +1 -1
- package/src/components/conversations-panel/conversations-panel.styles.ts +294 -294
- package/src/components/conversations-panel/conversations-panel.template.ts +184 -184
- package/src/components/fullscreen/fullscreen.styles.ts +185 -178
- package/src/components/mini-panel/mini-panel.styles.ts +346 -337
- package/src/components/rio-assist/rio-assist.ts +281 -255
|
@@ -39,12 +39,12 @@ export class RioAssistWidget extends LitElement {
|
|
|
39
39
|
errorMessage: { type: String, state: true },
|
|
40
40
|
showConversations: { type: Boolean, state: true },
|
|
41
41
|
conversationSearch: { type: String, state: true },
|
|
42
|
-
conversationMenuId: { state: true },
|
|
43
|
-
conversationMenuPlacement: { state: true },
|
|
44
|
-
isFullscreen: { type: Boolean, state: true },
|
|
45
|
-
conversationScrollbar: { state: true },
|
|
46
|
-
showNewConversationShortcut: { type: Boolean, state: true },
|
|
47
|
-
};
|
|
42
|
+
conversationMenuId: { state: true },
|
|
43
|
+
conversationMenuPlacement: { state: true },
|
|
44
|
+
isFullscreen: { type: Boolean, state: true },
|
|
45
|
+
conversationScrollbar: { state: true },
|
|
46
|
+
showNewConversationShortcut: { type: Boolean, state: true },
|
|
47
|
+
};
|
|
48
48
|
|
|
49
49
|
open = false;
|
|
50
50
|
|
|
@@ -74,37 +74,37 @@ export class RioAssistWidget extends LitElement {
|
|
|
74
74
|
|
|
75
75
|
conversationSearch = '';
|
|
76
76
|
|
|
77
|
-
conversationMenuId: string | null = null;
|
|
78
|
-
|
|
79
|
-
conversationMenuPlacement: 'above' | 'below' = 'below';
|
|
80
|
-
|
|
81
|
-
isFullscreen = false;
|
|
82
|
-
|
|
83
|
-
showNewConversationShortcut = false;
|
|
84
|
-
|
|
85
|
-
conversationScrollbar = {
|
|
86
|
-
height: 0,
|
|
87
|
-
top: 0,
|
|
88
|
-
visible: false,
|
|
89
|
-
};
|
|
90
|
-
|
|
91
|
-
private conversationScrollbarRaf: number | null = null;
|
|
92
|
-
|
|
93
|
-
private rioClient: RioWebsocketClient | null = null;
|
|
94
|
-
|
|
95
|
-
private rioUnsubscribe: (() => void) | null = null;
|
|
96
|
-
|
|
97
|
-
private loadingTimer: number | null = null;
|
|
98
|
-
|
|
99
|
-
private conversationScrollbarDraggingId: number | null = null;
|
|
100
|
-
|
|
101
|
-
private conversationScrollbarDragState: {
|
|
102
|
-
startY: number;
|
|
103
|
-
startThumbTop: number;
|
|
104
|
-
trackHeight: number;
|
|
105
|
-
thumbHeight: number;
|
|
106
|
-
list: HTMLElement;
|
|
107
|
-
} | null = null;
|
|
77
|
+
conversationMenuId: string | null = null;
|
|
78
|
+
|
|
79
|
+
conversationMenuPlacement: 'above' | 'below' = 'below';
|
|
80
|
+
|
|
81
|
+
isFullscreen = false;
|
|
82
|
+
|
|
83
|
+
showNewConversationShortcut = false;
|
|
84
|
+
|
|
85
|
+
conversationScrollbar = {
|
|
86
|
+
height: 0,
|
|
87
|
+
top: 0,
|
|
88
|
+
visible: false,
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
private conversationScrollbarRaf: number | null = null;
|
|
92
|
+
|
|
93
|
+
private rioClient: RioWebsocketClient | null = null;
|
|
94
|
+
|
|
95
|
+
private rioUnsubscribe: (() => void) | null = null;
|
|
96
|
+
|
|
97
|
+
private loadingTimer: number | null = null;
|
|
98
|
+
|
|
99
|
+
private conversationScrollbarDraggingId: number | null = null;
|
|
100
|
+
|
|
101
|
+
private conversationScrollbarDragState: {
|
|
102
|
+
startY: number;
|
|
103
|
+
startThumbTop: number;
|
|
104
|
+
trackHeight: number;
|
|
105
|
+
thumbHeight: number;
|
|
106
|
+
list: HTMLElement;
|
|
107
|
+
} | null = null;
|
|
108
108
|
|
|
109
109
|
conversations: ConversationItem[] = Array.from({ length: 20 }).map(
|
|
110
110
|
(_, index) => ({
|
|
@@ -141,14 +141,23 @@ export class RioAssistWidget extends LitElement {
|
|
|
141
141
|
super.updated(changedProperties);
|
|
142
142
|
this.style.setProperty('--accent-color', this.accentColor);
|
|
143
143
|
|
|
144
|
-
if (
|
|
145
|
-
changedProperties.has('isFullscreen') ||
|
|
146
|
-
changedProperties.has('showConversations') ||
|
|
147
|
-
changedProperties.has('conversations')
|
|
148
|
-
) {
|
|
149
|
-
this.enqueueConversationScrollbarMeasure();
|
|
150
|
-
}
|
|
151
|
-
|
|
144
|
+
if (
|
|
145
|
+
changedProperties.has('isFullscreen') ||
|
|
146
|
+
changedProperties.has('showConversations') ||
|
|
147
|
+
changedProperties.has('conversations')
|
|
148
|
+
) {
|
|
149
|
+
this.enqueueConversationScrollbarMeasure();
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
if (
|
|
153
|
+
changedProperties.has('messages') ||
|
|
154
|
+
(changedProperties.has('isLoading') && this.isLoading) ||
|
|
155
|
+
(changedProperties.has('open') && this.open) ||
|
|
156
|
+
(changedProperties.has('isFullscreen') && this.isFullscreen)
|
|
157
|
+
) {
|
|
158
|
+
this.scrollConversationToBottom();
|
|
159
|
+
}
|
|
160
|
+
}
|
|
152
161
|
|
|
153
162
|
protected firstUpdated(): void {
|
|
154
163
|
this.enqueueConversationScrollbarMeasure();
|
|
@@ -165,21 +174,21 @@ export class RioAssistWidget extends LitElement {
|
|
|
165
174
|
this.clearLoadingGuard();
|
|
166
175
|
}
|
|
167
176
|
|
|
168
|
-
get filteredConversations() {
|
|
169
|
-
const query = this.conversationSearch.trim().toLowerCase();
|
|
170
|
-
if (!query) {
|
|
171
|
-
return this.conversations;
|
|
172
|
-
}
|
|
177
|
+
get filteredConversations() {
|
|
178
|
+
const query = this.conversationSearch.trim().toLowerCase();
|
|
179
|
+
if (!query) {
|
|
180
|
+
return this.conversations;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
return this.conversations.filter((conversation) =>
|
|
184
|
+
conversation.title.toLowerCase().includes(query),
|
|
185
|
+
);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
get hasActiveConversation() {
|
|
189
|
+
return this.messages.length > 0;
|
|
190
|
+
}
|
|
173
191
|
|
|
174
|
-
return this.conversations.filter((conversation) =>
|
|
175
|
-
conversation.title.toLowerCase().includes(query),
|
|
176
|
-
);
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
get hasActiveConversation() {
|
|
180
|
-
return this.messages.length > 0;
|
|
181
|
-
}
|
|
182
|
-
|
|
183
192
|
togglePanel() {
|
|
184
193
|
if (this.isFullscreen) {
|
|
185
194
|
this.exitFullscreen(false);
|
|
@@ -211,20 +220,20 @@ export class RioAssistWidget extends LitElement {
|
|
|
211
220
|
this.conversationMenuId = null;
|
|
212
221
|
}
|
|
213
222
|
|
|
214
|
-
toggleConversationsPanel() {
|
|
215
|
-
this.showConversations = !this.showConversations;
|
|
216
|
-
if (!this.showConversations) {
|
|
217
|
-
this.conversationMenuId = null;
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
toggleNewConversationShortcut() {
|
|
222
|
-
this.showNewConversationShortcut = !this.showNewConversationShortcut;
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
handleConversationSearch(event: InputEvent) {
|
|
226
|
-
this.conversationSearch = (event.target as HTMLInputElement).value;
|
|
227
|
-
}
|
|
223
|
+
toggleConversationsPanel() {
|
|
224
|
+
this.showConversations = !this.showConversations;
|
|
225
|
+
if (!this.showConversations) {
|
|
226
|
+
this.conversationMenuId = null;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
toggleNewConversationShortcut() {
|
|
231
|
+
this.showNewConversationShortcut = !this.showNewConversationShortcut;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
handleConversationSearch(event: InputEvent) {
|
|
235
|
+
this.conversationSearch = (event.target as HTMLInputElement).value;
|
|
236
|
+
}
|
|
228
237
|
|
|
229
238
|
handleConversationMenuToggle(event: Event, id: string) {
|
|
230
239
|
event.stopPropagation();
|
|
@@ -297,134 +306,134 @@ export class RioAssistWidget extends LitElement {
|
|
|
297
306
|
this.showConversations = false;
|
|
298
307
|
}
|
|
299
308
|
|
|
300
|
-
exitFullscreen(restorePanel: boolean) {
|
|
301
|
-
if (!this.isFullscreen) {
|
|
302
|
-
return;
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
this.isFullscreen = false;
|
|
306
|
-
this.conversationMenuId = null;
|
|
307
|
-
this.showNewConversationShortcut = false;
|
|
308
|
-
if (restorePanel) {
|
|
309
|
-
this.open = true;
|
|
310
|
-
}
|
|
311
|
-
}
|
|
309
|
+
exitFullscreen(restorePanel: boolean) {
|
|
310
|
+
if (!this.isFullscreen) {
|
|
311
|
+
return;
|
|
312
|
+
}
|
|
312
313
|
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
this.
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
this.
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
314
|
+
this.isFullscreen = false;
|
|
315
|
+
this.conversationMenuId = null;
|
|
316
|
+
this.showNewConversationShortcut = false;
|
|
317
|
+
if (restorePanel) {
|
|
318
|
+
this.open = true;
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
handleCreateConversation() {
|
|
323
|
+
if (!this.hasActiveConversation) {
|
|
324
|
+
return;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
this.clearLoadingGuard();
|
|
328
|
+
this.isLoading = false;
|
|
329
|
+
this.messages = [];
|
|
330
|
+
this.message = '';
|
|
331
|
+
this.errorMessage = '';
|
|
332
|
+
this.showConversations = false;
|
|
333
|
+
this.teardownRioClient();
|
|
334
|
+
this.showNewConversationShortcut = false;
|
|
335
|
+
this.dispatchEvent(
|
|
336
|
+
new CustomEvent('rioassist:new-conversation', {
|
|
337
|
+
bubbles: true,
|
|
338
|
+
composed: true,
|
|
339
|
+
}),
|
|
340
|
+
);
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
handleConversationListScroll(event: Event) {
|
|
344
|
+
const target = event.currentTarget as HTMLElement | null;
|
|
345
|
+
if (!target) {
|
|
346
|
+
return;
|
|
347
|
+
}
|
|
348
|
+
this.updateConversationScrollbar(target);
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
handleConversationScrollbarPointerDown(event: PointerEvent) {
|
|
352
|
+
const track = event.currentTarget as HTMLElement | null;
|
|
353
|
+
const list = this.renderRoot.querySelector(
|
|
354
|
+
'.conversation-list--sidebar',
|
|
355
|
+
) as HTMLElement | null;
|
|
356
|
+
|
|
357
|
+
if (!track || !list) {
|
|
358
|
+
return;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
const trackRect = track.getBoundingClientRect();
|
|
362
|
+
const thumbHeight = trackRect.height * (this.conversationScrollbar.height / 100);
|
|
363
|
+
const maxThumbTop = Math.max(trackRect.height - thumbHeight, 0);
|
|
364
|
+
const scrollRange = Math.max(list.scrollHeight - list.clientHeight, 1);
|
|
365
|
+
const currentThumbTop = (list.scrollTop / scrollRange) * maxThumbTop;
|
|
366
|
+
const offsetY = event.clientY - trackRect.top;
|
|
367
|
+
const isOnThumb = offsetY >= currentThumbTop && offsetY <= currentThumbTop + thumbHeight;
|
|
368
|
+
|
|
369
|
+
const nextThumbTop = isOnThumb
|
|
370
|
+
? currentThumbTop
|
|
371
|
+
: Math.min(Math.max(offsetY - thumbHeight / 2, 0), maxThumbTop);
|
|
372
|
+
|
|
373
|
+
if (!isOnThumb) {
|
|
374
|
+
list.scrollTop = (nextThumbTop / Math.max(maxThumbTop, 1)) * (list.scrollHeight - list.clientHeight);
|
|
375
|
+
this.updateConversationScrollbar(list);
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
track.setPointerCapture(event.pointerId);
|
|
379
|
+
this.conversationScrollbarDraggingId = event.pointerId;
|
|
380
|
+
this.conversationScrollbarDragState = {
|
|
381
|
+
startY: event.clientY,
|
|
382
|
+
startThumbTop: nextThumbTop,
|
|
383
|
+
trackHeight: trackRect.height,
|
|
384
|
+
thumbHeight,
|
|
385
|
+
list,
|
|
386
|
+
};
|
|
387
|
+
event.preventDefault();
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
handleConversationScrollbarPointerMove(event: PointerEvent) {
|
|
391
|
+
if (
|
|
392
|
+
this.conversationScrollbarDraggingId === null ||
|
|
393
|
+
this.conversationScrollbarDraggingId !== event.pointerId ||
|
|
394
|
+
!this.conversationScrollbarDragState
|
|
395
|
+
) {
|
|
396
|
+
return;
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
const {
|
|
400
|
+
startY,
|
|
401
|
+
startThumbTop,
|
|
402
|
+
trackHeight,
|
|
403
|
+
thumbHeight,
|
|
404
|
+
list,
|
|
405
|
+
} = this.conversationScrollbarDragState;
|
|
406
|
+
|
|
407
|
+
const maxThumbTop = Math.max(trackHeight - thumbHeight, 0);
|
|
408
|
+
const deltaY = event.clientY - startY;
|
|
409
|
+
const thumbTop = Math.min(Math.max(startThumbTop + deltaY, 0), maxThumbTop);
|
|
410
|
+
const scrollRange = list.scrollHeight - list.clientHeight;
|
|
411
|
+
|
|
412
|
+
if (scrollRange > 0) {
|
|
413
|
+
list.scrollTop = (thumbTop / Math.max(maxThumbTop, 1)) * scrollRange;
|
|
414
|
+
this.updateConversationScrollbar(list);
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
event.preventDefault();
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
handleConversationScrollbarPointerUp(event: PointerEvent) {
|
|
421
|
+
if (this.conversationScrollbarDraggingId !== event.pointerId) {
|
|
422
|
+
return;
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
const track = event.currentTarget as HTMLElement | null;
|
|
426
|
+
track?.releasePointerCapture(event.pointerId);
|
|
427
|
+
|
|
428
|
+
this.conversationScrollbarDraggingId = null;
|
|
429
|
+
this.conversationScrollbarDragState = null;
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
private enqueueConversationScrollbarMeasure() {
|
|
433
|
+
if (this.conversationScrollbarRaf !== null) {
|
|
434
|
+
return;
|
|
435
|
+
}
|
|
333
436
|
|
|
334
|
-
handleConversationListScroll(event: Event) {
|
|
335
|
-
const target = event.currentTarget as HTMLElement | null;
|
|
336
|
-
if (!target) {
|
|
337
|
-
return;
|
|
338
|
-
}
|
|
339
|
-
this.updateConversationScrollbar(target);
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
handleConversationScrollbarPointerDown(event: PointerEvent) {
|
|
343
|
-
const track = event.currentTarget as HTMLElement | null;
|
|
344
|
-
const list = this.renderRoot.querySelector(
|
|
345
|
-
'.conversation-list--sidebar',
|
|
346
|
-
) as HTMLElement | null;
|
|
347
|
-
|
|
348
|
-
if (!track || !list) {
|
|
349
|
-
return;
|
|
350
|
-
}
|
|
351
|
-
|
|
352
|
-
const trackRect = track.getBoundingClientRect();
|
|
353
|
-
const thumbHeight = trackRect.height * (this.conversationScrollbar.height / 100);
|
|
354
|
-
const maxThumbTop = Math.max(trackRect.height - thumbHeight, 0);
|
|
355
|
-
const scrollRange = Math.max(list.scrollHeight - list.clientHeight, 1);
|
|
356
|
-
const currentThumbTop = (list.scrollTop / scrollRange) * maxThumbTop;
|
|
357
|
-
const offsetY = event.clientY - trackRect.top;
|
|
358
|
-
const isOnThumb = offsetY >= currentThumbTop && offsetY <= currentThumbTop + thumbHeight;
|
|
359
|
-
|
|
360
|
-
const nextThumbTop = isOnThumb
|
|
361
|
-
? currentThumbTop
|
|
362
|
-
: Math.min(Math.max(offsetY - thumbHeight / 2, 0), maxThumbTop);
|
|
363
|
-
|
|
364
|
-
if (!isOnThumb) {
|
|
365
|
-
list.scrollTop = (nextThumbTop / Math.max(maxThumbTop, 1)) * (list.scrollHeight - list.clientHeight);
|
|
366
|
-
this.updateConversationScrollbar(list);
|
|
367
|
-
}
|
|
368
|
-
|
|
369
|
-
track.setPointerCapture(event.pointerId);
|
|
370
|
-
this.conversationScrollbarDraggingId = event.pointerId;
|
|
371
|
-
this.conversationScrollbarDragState = {
|
|
372
|
-
startY: event.clientY,
|
|
373
|
-
startThumbTop: nextThumbTop,
|
|
374
|
-
trackHeight: trackRect.height,
|
|
375
|
-
thumbHeight,
|
|
376
|
-
list,
|
|
377
|
-
};
|
|
378
|
-
event.preventDefault();
|
|
379
|
-
}
|
|
380
|
-
|
|
381
|
-
handleConversationScrollbarPointerMove(event: PointerEvent) {
|
|
382
|
-
if (
|
|
383
|
-
this.conversationScrollbarDraggingId === null ||
|
|
384
|
-
this.conversationScrollbarDraggingId !== event.pointerId ||
|
|
385
|
-
!this.conversationScrollbarDragState
|
|
386
|
-
) {
|
|
387
|
-
return;
|
|
388
|
-
}
|
|
389
|
-
|
|
390
|
-
const {
|
|
391
|
-
startY,
|
|
392
|
-
startThumbTop,
|
|
393
|
-
trackHeight,
|
|
394
|
-
thumbHeight,
|
|
395
|
-
list,
|
|
396
|
-
} = this.conversationScrollbarDragState;
|
|
397
|
-
|
|
398
|
-
const maxThumbTop = Math.max(trackHeight - thumbHeight, 0);
|
|
399
|
-
const deltaY = event.clientY - startY;
|
|
400
|
-
const thumbTop = Math.min(Math.max(startThumbTop + deltaY, 0), maxThumbTop);
|
|
401
|
-
const scrollRange = list.scrollHeight - list.clientHeight;
|
|
402
|
-
|
|
403
|
-
if (scrollRange > 0) {
|
|
404
|
-
list.scrollTop = (thumbTop / Math.max(maxThumbTop, 1)) * scrollRange;
|
|
405
|
-
this.updateConversationScrollbar(list);
|
|
406
|
-
}
|
|
407
|
-
|
|
408
|
-
event.preventDefault();
|
|
409
|
-
}
|
|
410
|
-
|
|
411
|
-
handleConversationScrollbarPointerUp(event: PointerEvent) {
|
|
412
|
-
if (this.conversationScrollbarDraggingId !== event.pointerId) {
|
|
413
|
-
return;
|
|
414
|
-
}
|
|
415
|
-
|
|
416
|
-
const track = event.currentTarget as HTMLElement | null;
|
|
417
|
-
track?.releasePointerCapture(event.pointerId);
|
|
418
|
-
|
|
419
|
-
this.conversationScrollbarDraggingId = null;
|
|
420
|
-
this.conversationScrollbarDragState = null;
|
|
421
|
-
}
|
|
422
|
-
|
|
423
|
-
private enqueueConversationScrollbarMeasure() {
|
|
424
|
-
if (this.conversationScrollbarRaf !== null) {
|
|
425
|
-
return;
|
|
426
|
-
}
|
|
427
|
-
|
|
428
437
|
this.conversationScrollbarRaf = requestAnimationFrame(() => {
|
|
429
438
|
this.conversationScrollbarRaf = null;
|
|
430
439
|
this.updateConversationScrollbar();
|
|
@@ -453,22 +462,22 @@ export class RioAssistWidget extends LitElement {
|
|
|
453
462
|
return;
|
|
454
463
|
}
|
|
455
464
|
|
|
456
|
-
const ratio = clientHeight / scrollHeight;
|
|
457
|
-
const height = Math.max(ratio * 100, 8);
|
|
458
|
-
const maxTop = 100 - height;
|
|
459
|
-
const top =
|
|
460
|
-
scrollTop / (scrollHeight - clientHeight) * (maxTop > 0 ? maxTop : 0);
|
|
461
|
-
|
|
462
|
-
this.conversationScrollbar = {
|
|
463
|
-
height,
|
|
464
|
-
top,
|
|
465
|
-
visible: true,
|
|
466
|
-
};
|
|
467
|
-
}
|
|
468
|
-
|
|
469
|
-
async onSuggestionClick(suggestion: string) {
|
|
470
|
-
await this.processMessage(suggestion);
|
|
471
|
-
}
|
|
465
|
+
const ratio = clientHeight / scrollHeight;
|
|
466
|
+
const height = Math.max(ratio * 100, 8);
|
|
467
|
+
const maxTop = 100 - height;
|
|
468
|
+
const top =
|
|
469
|
+
scrollTop / (scrollHeight - clientHeight) * (maxTop > 0 ? maxTop : 0);
|
|
470
|
+
|
|
471
|
+
this.conversationScrollbar = {
|
|
472
|
+
height,
|
|
473
|
+
top,
|
|
474
|
+
visible: true,
|
|
475
|
+
};
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
async onSuggestionClick(suggestion: string) {
|
|
479
|
+
await this.processMessage(suggestion);
|
|
480
|
+
}
|
|
472
481
|
|
|
473
482
|
async handleSubmit(event: SubmitEvent) {
|
|
474
483
|
event.preventDefault();
|
|
@@ -488,30 +497,35 @@ export class RioAssistWidget extends LitElement {
|
|
|
488
497
|
};
|
|
489
498
|
}
|
|
490
499
|
|
|
491
|
-
private async processMessage(rawValue: string) {
|
|
492
|
-
const content = rawValue.trim();
|
|
493
|
-
if (!content || this.isLoading) {
|
|
494
|
-
return;
|
|
495
|
-
}
|
|
496
|
-
|
|
497
|
-
this.
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
500
|
+
private async processMessage(rawValue: string) {
|
|
501
|
+
const content = rawValue.trim();
|
|
502
|
+
if (!content || this.isLoading) {
|
|
503
|
+
return;
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
const wasEmptyConversation = this.messages.length === 0;
|
|
507
|
+
|
|
508
|
+
this.dispatchEvent(
|
|
509
|
+
new CustomEvent('rioassist:send', {
|
|
510
|
+
detail: {
|
|
511
|
+
message: content,
|
|
512
|
+
apiBaseUrl: this.apiBaseUrl,
|
|
502
513
|
token: this.rioToken,
|
|
503
514
|
},
|
|
504
515
|
bubbles: true,
|
|
505
516
|
composed: true,
|
|
506
517
|
}),
|
|
507
518
|
);
|
|
508
|
-
|
|
509
|
-
const userMessage = this.createMessage('user', content);
|
|
510
|
-
this.messages = [...this.messages, userMessage];
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
this.
|
|
519
|
+
|
|
520
|
+
const userMessage = this.createMessage('user', content);
|
|
521
|
+
this.messages = [...this.messages, userMessage];
|
|
522
|
+
if (wasEmptyConversation) {
|
|
523
|
+
this.showNewConversationShortcut = true;
|
|
524
|
+
}
|
|
525
|
+
this.message = '';
|
|
526
|
+
this.errorMessage = '';
|
|
527
|
+
this.isLoading = true;
|
|
528
|
+
this.startLoadingGuard();
|
|
515
529
|
|
|
516
530
|
try {
|
|
517
531
|
const client = this.ensureRioClient();
|
|
@@ -525,11 +539,11 @@ export class RioAssistWidget extends LitElement {
|
|
|
525
539
|
}
|
|
526
540
|
}
|
|
527
541
|
|
|
528
|
-
private ensureRioClient() {
|
|
529
|
-
const token = this.rioToken.trim();
|
|
530
|
-
if (!token) {
|
|
531
|
-
throw new Error(
|
|
532
|
-
'Informe o token RIO em data-rio-token para conectar no websocket do assistente.',
|
|
542
|
+
private ensureRioClient() {
|
|
543
|
+
const token = this.rioToken.trim();
|
|
544
|
+
if (!token) {
|
|
545
|
+
throw new Error(
|
|
546
|
+
'Informe o token RIO em data-rio-token para conectar no websocket do assistente.',
|
|
533
547
|
);
|
|
534
548
|
}
|
|
535
549
|
|
|
@@ -566,23 +580,35 @@ export class RioAssistWidget extends LitElement {
|
|
|
566
580
|
private startLoadingGuard() {
|
|
567
581
|
this.clearLoadingGuard();
|
|
568
582
|
this.loadingTimer = window.setTimeout(() => {
|
|
569
|
-
this.loadingTimer = null;
|
|
570
|
-
this.isLoading = false;
|
|
571
|
-
}, 15000);
|
|
572
|
-
}
|
|
573
|
-
|
|
574
|
-
private clearLoadingGuard() {
|
|
575
|
-
if (this.loadingTimer !== null) {
|
|
576
|
-
window.clearTimeout(this.loadingTimer);
|
|
577
|
-
this.loadingTimer = null;
|
|
578
|
-
}
|
|
579
|
-
}
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
583
|
+
this.loadingTimer = null;
|
|
584
|
+
this.isLoading = false;
|
|
585
|
+
}, 15000);
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
private clearLoadingGuard() {
|
|
589
|
+
if (this.loadingTimer !== null) {
|
|
590
|
+
window.clearTimeout(this.loadingTimer);
|
|
591
|
+
this.loadingTimer = null;
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
private scrollConversationToBottom() {
|
|
596
|
+
const containers = Array.from(
|
|
597
|
+
this.renderRoot.querySelectorAll('.panel-content'),
|
|
598
|
+
) as HTMLElement[];
|
|
599
|
+
|
|
600
|
+
containers.forEach((container) => {
|
|
601
|
+
requestAnimationFrame(() => {
|
|
602
|
+
container.scrollTop = container.scrollHeight;
|
|
603
|
+
});
|
|
604
|
+
});
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
render() {
|
|
608
|
+
return renderRioAssist(this);
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
}
|
|
586
612
|
declare global {
|
|
587
613
|
interface HTMLElementTagNameMap {
|
|
588
614
|
'rio-assist-widget': RioAssistWidget;
|