@salesforcedevs/docs-components 0.0.11-edit → 0.0.12-chat
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/lwc.config.json +0 -1
- package/package.json +1 -1
- package/src/modules/doc/chat/chat.css +62 -638
- package/src/modules/doc/chat/chat.html +14 -192
- package/src/modules/doc/chat/chat.ts +33 -456
- package/src/modules/doc/contentLayout/contentLayout.html +17 -17
- package/src/modules/doc/chat/README.md +0 -179
- package/src/modules/doc/editFile/editFile.css +0 -613
- package/src/modules/doc/editFile/editFile.html +0 -225
- package/src/modules/doc/editFile/editFile.ts +0 -294
|
@@ -9,7 +9,6 @@ interface ChatMessage {
|
|
|
9
9
|
sender: "user" | "assistant";
|
|
10
10
|
isTyping?: boolean;
|
|
11
11
|
formattedTime?: string;
|
|
12
|
-
isHTML?: boolean; // Flag to indicate if content should be rendered as HTML
|
|
13
12
|
}
|
|
14
13
|
|
|
15
14
|
export default class Chat extends LightningElement {
|
|
@@ -17,7 +16,7 @@ export default class Chat extends LightningElement {
|
|
|
17
16
|
@api placeholder: string = "Type your message...";
|
|
18
17
|
@api assistantName: string = "Assistant";
|
|
19
18
|
@api maxHeight: string = "400px";
|
|
20
|
-
|
|
19
|
+
|
|
21
20
|
@api
|
|
22
21
|
get disabled() {
|
|
23
22
|
return this._disabled;
|
|
@@ -36,108 +35,26 @@ export default class Chat extends LightningElement {
|
|
|
36
35
|
this._showTimestamp = normalizeBoolean(value);
|
|
37
36
|
}
|
|
38
37
|
|
|
39
|
-
@api
|
|
40
|
-
get isOpen() {
|
|
41
|
-
return this._isOpen;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
set isOpen(value) {
|
|
45
|
-
this._isOpen = normalizeBoolean(value);
|
|
46
|
-
}
|
|
47
|
-
|
|
48
38
|
@track messages: ChatMessage[] = [];
|
|
49
39
|
@track currentMessage: string = "";
|
|
50
40
|
@track isAssistantTyping: boolean = false;
|
|
51
|
-
|
|
41
|
+
|
|
52
42
|
private _disabled: boolean = false;
|
|
53
43
|
private _showTimestamp: boolean = false;
|
|
54
|
-
private _isOpen: boolean = false;
|
|
55
44
|
private messageIdCounter: number = 0;
|
|
56
45
|
|
|
57
|
-
// API Configuration
|
|
58
|
-
private static readonly API_URL =
|
|
59
|
-
"https://276ca7264b79.ngrok-free.app/api/llm/search";
|
|
60
|
-
private static readonly MAX_RESULTS = 3;
|
|
61
|
-
|
|
62
|
-
// Development mode flag - set to true if running in development
|
|
63
|
-
private static readonly IS_DEVELOPMENT =
|
|
64
|
-
window.location.hostname === "localhost" ||
|
|
65
|
-
window.location.hostname === "127.0.0.1";
|
|
66
|
-
|
|
67
|
-
// localStorage keys for persisting messages and open state
|
|
68
|
-
private static readonly STORAGE_KEY = "doc-chat-messages";
|
|
69
|
-
private static readonly OPEN_STATE_KEY = "doc-chat-should-open";
|
|
70
|
-
|
|
71
46
|
connectedCallback() {
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
this.loadMessages();
|
|
75
|
-
|
|
76
|
-
// Add welcome message only if no existing messages
|
|
77
|
-
if (this.messages.length === 0) {
|
|
78
|
-
this.addMessage("Hello! How can I help you today?", "assistant");
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
// Check if chat should be opened after reload
|
|
82
|
-
this.checkAndOpenAfterReload();
|
|
83
|
-
|
|
84
|
-
// Ensure body has proper class state
|
|
85
|
-
this.updateBodyClass();
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
disconnectedCallback() {
|
|
89
|
-
// Clean up body classes when component is destroyed
|
|
90
|
-
document.body.classList.remove("chat-open", "chat-closed");
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
renderedCallback() {
|
|
94
|
-
// Handle HTML content rendering for messages with isHTML flag
|
|
95
|
-
this.renderHTMLMessages();
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
private renderHTMLMessages() {
|
|
99
|
-
console.log("=== renderHTMLMessages called ===");
|
|
100
|
-
console.log("All messages:", this.messages);
|
|
101
|
-
console.log(
|
|
102
|
-
"HTML messages:",
|
|
103
|
-
this.messages.filter((msg) => msg.isHTML)
|
|
104
|
-
);
|
|
105
|
-
|
|
106
|
-
// Use a simpler selector approach
|
|
107
|
-
const htmlMessageElements = this.template.querySelectorAll(
|
|
108
|
-
".html-content[data-message-id]"
|
|
109
|
-
);
|
|
110
|
-
console.log("Found HTML elements:", htmlMessageElements.length);
|
|
111
|
-
|
|
112
|
-
htmlMessageElements.forEach((element) => {
|
|
113
|
-
const messageId = element.getAttribute("data-message-id");
|
|
114
|
-
console.log("Processing element with ID:", messageId);
|
|
115
|
-
|
|
116
|
-
const message = this.messages.find(
|
|
117
|
-
(msg) => msg.id === messageId && msg.isHTML
|
|
118
|
-
);
|
|
119
|
-
console.log("Found message:", message);
|
|
120
|
-
|
|
121
|
-
if (message) {
|
|
122
|
-
console.log("Setting innerHTML for message:", messageId);
|
|
123
|
-
console.log("Content:", message.text);
|
|
124
|
-
element.innerHTML = message.text;
|
|
125
|
-
}
|
|
126
|
-
});
|
|
47
|
+
// Add a welcome message
|
|
48
|
+
this.addMessage("Hello! How can I help you today?", "assistant");
|
|
127
49
|
}
|
|
128
50
|
|
|
129
51
|
get chatContainerClass() {
|
|
130
52
|
return cx(
|
|
131
53
|
"chat-container",
|
|
132
|
-
this.disabled && "chat-
|
|
133
|
-
this.isOpen && "chat-container_open"
|
|
54
|
+
this.disabled && "chat-container--disabled"
|
|
134
55
|
);
|
|
135
56
|
}
|
|
136
57
|
|
|
137
|
-
get showTriggerButton() {
|
|
138
|
-
return !this.isOpen;
|
|
139
|
-
}
|
|
140
|
-
|
|
141
58
|
get messagesWithTyping() {
|
|
142
59
|
const messages = [...this.messages];
|
|
143
60
|
if (this.isAssistantTyping) {
|
|
@@ -154,151 +71,36 @@ export default class Chat extends LightningElement {
|
|
|
154
71
|
return messages;
|
|
155
72
|
}
|
|
156
73
|
|
|
157
|
-
|
|
158
|
-
getMessageHTML(messageId: string): string {
|
|
159
|
-
const message = this.messages.find(
|
|
160
|
-
(msg) => msg.id === messageId && msg.isHTML
|
|
161
|
-
);
|
|
162
|
-
return message ? message.text : "";
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
private addMessage(
|
|
166
|
-
text: string,
|
|
167
|
-
sender: "user" | "assistant",
|
|
168
|
-
isHTML: boolean = false
|
|
169
|
-
) {
|
|
74
|
+
private addMessage(text: string, sender: "user" | "assistant") {
|
|
170
75
|
const timestamp = new Date();
|
|
171
76
|
const message: ChatMessage = {
|
|
172
77
|
id: `msg-${this.messageIdCounter++}`,
|
|
173
78
|
text,
|
|
174
79
|
timestamp,
|
|
175
80
|
sender,
|
|
176
|
-
formattedTime: this.formatTimestamp(timestamp)
|
|
177
|
-
isHTML
|
|
81
|
+
formattedTime: this.formatTimestamp(timestamp)
|
|
178
82
|
};
|
|
179
83
|
this.messages = [...this.messages, message];
|
|
180
|
-
this.saveMessages();
|
|
181
84
|
this.scrollToBottom();
|
|
182
85
|
}
|
|
183
86
|
|
|
184
87
|
private scrollToBottom() {
|
|
185
88
|
// Use setTimeout to ensure DOM is updated
|
|
186
89
|
setTimeout(() => {
|
|
187
|
-
const messagesContainer =
|
|
188
|
-
this.template.querySelector(".chat-messages");
|
|
90
|
+
const messagesContainer = this.template.querySelector('.chat-messages');
|
|
189
91
|
if (messagesContainer) {
|
|
190
92
|
messagesContainer.scrollTop = messagesContainer.scrollHeight;
|
|
191
93
|
}
|
|
192
94
|
}, 0);
|
|
193
95
|
}
|
|
194
96
|
|
|
195
|
-
private updateBodyClass() {
|
|
196
|
-
// Update body classes to trigger content shift
|
|
197
|
-
if (this.isOpen) {
|
|
198
|
-
document.body.classList.remove("chat-closed");
|
|
199
|
-
document.body.classList.add("chat-open");
|
|
200
|
-
} else {
|
|
201
|
-
document.body.classList.remove("chat-open");
|
|
202
|
-
document.body.classList.add("chat-closed");
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
private saveMessages() {
|
|
207
|
-
try {
|
|
208
|
-
const messagesToSave = this.messages.map((msg) => ({
|
|
209
|
-
id: msg.id,
|
|
210
|
-
text: msg.text,
|
|
211
|
-
timestamp: msg.timestamp.toISOString(),
|
|
212
|
-
sender: msg.sender,
|
|
213
|
-
formattedTime: msg.formattedTime,
|
|
214
|
-
isHTML: msg.isHTML || false
|
|
215
|
-
}));
|
|
216
|
-
localStorage.setItem(
|
|
217
|
-
Chat.STORAGE_KEY,
|
|
218
|
-
JSON.stringify(messagesToSave)
|
|
219
|
-
);
|
|
220
|
-
} catch (error) {
|
|
221
|
-
console.warn("Failed to save messages to localStorage:", error);
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
private loadMessages() {
|
|
226
|
-
try {
|
|
227
|
-
const savedMessages = localStorage.getItem(Chat.STORAGE_KEY);
|
|
228
|
-
if (savedMessages) {
|
|
229
|
-
const parsedMessages = JSON.parse(savedMessages);
|
|
230
|
-
this.messages = parsedMessages.map((msg: any) => ({
|
|
231
|
-
id: msg.id,
|
|
232
|
-
text: msg.text,
|
|
233
|
-
timestamp: new Date(msg.timestamp),
|
|
234
|
-
sender: msg.sender,
|
|
235
|
-
formattedTime: msg.formattedTime,
|
|
236
|
-
isHTML: msg.isHTML || false
|
|
237
|
-
}));
|
|
238
|
-
|
|
239
|
-
// Update message counter to avoid ID conflicts
|
|
240
|
-
const lastId =
|
|
241
|
-
this.messages.length > 0
|
|
242
|
-
? Math.max(
|
|
243
|
-
...this.messages.map(
|
|
244
|
-
(m) =>
|
|
245
|
-
parseInt(m.id.replace("msg-", ""), 10) ||
|
|
246
|
-
0
|
|
247
|
-
)
|
|
248
|
-
)
|
|
249
|
-
: 0;
|
|
250
|
-
this.messageIdCounter = lastId + 1;
|
|
251
|
-
}
|
|
252
|
-
} catch (error) {
|
|
253
|
-
console.warn("Failed to load messages from localStorage:", error);
|
|
254
|
-
this.messages = [];
|
|
255
|
-
}
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
private clearMessages() {
|
|
259
|
-
try {
|
|
260
|
-
localStorage.removeItem(Chat.STORAGE_KEY);
|
|
261
|
-
this.messages = [];
|
|
262
|
-
this.messageIdCounter = 0;
|
|
263
|
-
// Add welcome message after clearing
|
|
264
|
-
this.addMessage("Hello! How can I help you today?", "assistant");
|
|
265
|
-
} catch (error) {
|
|
266
|
-
console.warn("Failed to clear messages from localStorage:", error);
|
|
267
|
-
}
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
private checkAndOpenAfterReload() {
|
|
271
|
-
try {
|
|
272
|
-
const shouldOpen = localStorage.getItem(Chat.OPEN_STATE_KEY);
|
|
273
|
-
if (shouldOpen === "true") {
|
|
274
|
-
// Clear the flag
|
|
275
|
-
localStorage.removeItem(Chat.OPEN_STATE_KEY);
|
|
276
|
-
// Open the chat
|
|
277
|
-
this._isOpen = true;
|
|
278
|
-
this.updateBodyClass();
|
|
279
|
-
|
|
280
|
-
// Dispatch custom event to notify parent components
|
|
281
|
-
this.dispatchEvent(
|
|
282
|
-
new CustomEvent("chatopened", {
|
|
283
|
-
detail: { opened: true }
|
|
284
|
-
})
|
|
285
|
-
);
|
|
286
|
-
}
|
|
287
|
-
} catch (error) {
|
|
288
|
-
console.warn(
|
|
289
|
-
"Failed to check open state from localStorage:",
|
|
290
|
-
error
|
|
291
|
-
);
|
|
292
|
-
}
|
|
293
|
-
}
|
|
294
|
-
|
|
295
97
|
handleInputChange(event: Event) {
|
|
296
98
|
const target = event.target as HTMLInputElement;
|
|
297
99
|
this.currentMessage = target.value;
|
|
298
100
|
}
|
|
299
101
|
|
|
300
102
|
handleKeyDown(event: KeyboardEvent) {
|
|
301
|
-
if (event.key ===
|
|
103
|
+
if (event.key === 'Enter' && !event.shiftKey) {
|
|
302
104
|
event.preventDefault();
|
|
303
105
|
this.sendMessage();
|
|
304
106
|
}
|
|
@@ -319,268 +121,43 @@ export default class Chat extends LightningElement {
|
|
|
319
121
|
this.currentMessage = "";
|
|
320
122
|
|
|
321
123
|
// Clear input
|
|
322
|
-
const input = this.template.querySelector(
|
|
323
|
-
".chat-input"
|
|
324
|
-
) as HTMLInputElement;
|
|
124
|
+
const input = this.template.querySelector('.chat-input') as HTMLInputElement;
|
|
325
125
|
if (input) {
|
|
326
126
|
input.value = "";
|
|
327
127
|
}
|
|
328
128
|
|
|
329
|
-
//
|
|
129
|
+
// Simulate assistant typing
|
|
330
130
|
this.isAssistantTyping = true;
|
|
331
|
-
|
|
332
|
-
//
|
|
333
|
-
// Add a small delay to show the typing indicator
|
|
131
|
+
|
|
132
|
+
// Simulate assistant response after a delay
|
|
334
133
|
setTimeout(() => {
|
|
335
|
-
this.getAssistantResponse(userMessage);
|
|
336
|
-
}, 500);
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
private async callChatAPI(userMessage: string): Promise<string> {
|
|
340
|
-
try {
|
|
341
|
-
// Format chat history for API (exclude the current user message)
|
|
342
|
-
const chatHistory = this.messages.map((msg) => ({
|
|
343
|
-
text: msg.text,
|
|
344
|
-
sender: msg.sender
|
|
345
|
-
}));
|
|
346
|
-
|
|
347
|
-
const requestBody = {
|
|
348
|
-
query: userMessage,
|
|
349
|
-
maxResults: Chat.MAX_RESULTS,
|
|
350
|
-
chatHistory: chatHistory
|
|
351
|
-
};
|
|
352
|
-
|
|
353
|
-
console.log("Sending API request:", requestBody);
|
|
354
|
-
|
|
355
|
-
const response = await fetch(Chat.API_URL, {
|
|
356
|
-
method: "POST",
|
|
357
|
-
headers: {
|
|
358
|
-
"Content-Type": "application/json",
|
|
359
|
-
"ngrok-skip-browser-warning": "true" // Skip ngrok browser warning
|
|
360
|
-
},
|
|
361
|
-
body: JSON.stringify(requestBody)
|
|
362
|
-
});
|
|
363
|
-
|
|
364
|
-
if (!response.ok) {
|
|
365
|
-
const errorText = await response.text();
|
|
366
|
-
console.error("API Error Response:", errorText);
|
|
367
|
-
throw new Error(
|
|
368
|
-
`API request failed with status: ${response.status}`
|
|
369
|
-
);
|
|
370
|
-
}
|
|
371
|
-
|
|
372
|
-
const data = await response.json();
|
|
373
|
-
console.log("API Response:", data);
|
|
374
|
-
|
|
375
|
-
// Handle the new API response format with "data" field
|
|
376
|
-
const responseText =
|
|
377
|
-
data.data ||
|
|
378
|
-
data.answer ||
|
|
379
|
-
data.text ||
|
|
380
|
-
data.response ||
|
|
381
|
-
data.result ||
|
|
382
|
-
data.message;
|
|
383
|
-
console.log("Response Text:", responseText);
|
|
384
|
-
|
|
385
|
-
if (!responseText) {
|
|
386
|
-
console.warn("No response text found in API response:", data);
|
|
387
|
-
return "I received your message but couldn't generate a proper response.";
|
|
388
|
-
}
|
|
389
|
-
|
|
390
|
-
return responseText;
|
|
391
|
-
} catch (error) {
|
|
392
|
-
console.error("Chat API error:", error);
|
|
393
|
-
|
|
394
|
-
// Provide more specific error messages for CORS issues
|
|
395
|
-
if (error instanceof TypeError && error.message.includes("fetch")) {
|
|
396
|
-
return "I'm having trouble connecting to the service. This might be a CORS configuration issue. Please check your internet connection and try again.";
|
|
397
|
-
}
|
|
398
|
-
|
|
399
|
-
if (
|
|
400
|
-
error instanceof Error &&
|
|
401
|
-
(error.message.includes("CORS") ||
|
|
402
|
-
error.message.includes("cross-origin"))
|
|
403
|
-
) {
|
|
404
|
-
return "I'm having trouble connecting due to browser security restrictions. Please ask your administrator to configure CORS headers on the backend API.";
|
|
405
|
-
}
|
|
406
|
-
|
|
407
|
-
return "I apologize, but I'm having trouble connecting to the service right now. Please try again later.";
|
|
408
|
-
}
|
|
409
|
-
}
|
|
410
|
-
|
|
411
|
-
private parseMarkdownToHTML(text: string): string {
|
|
412
|
-
// Convert markdown-like text to HTML
|
|
413
|
-
let html = text;
|
|
414
|
-
|
|
415
|
-
console.log("Original text:", text);
|
|
416
|
-
|
|
417
|
-
// First, convert markdown links [text](url) to HTML links
|
|
418
|
-
// Make sure links are absolute (relative to root) by adding leading slash if missing
|
|
419
|
-
html = html.replace(
|
|
420
|
-
/\[([^\]]+)\]\(([^)]+)\)/g,
|
|
421
|
-
(match, linkText, url) => {
|
|
422
|
-
// If URL doesn't start with http, https, or /, make it absolute
|
|
423
|
-
let absoluteUrl = url;
|
|
424
|
-
if (!url.startsWith("http") && !url.startsWith("/")) {
|
|
425
|
-
absoluteUrl = "/" + url;
|
|
426
|
-
}
|
|
427
|
-
return `<a href="${absoluteUrl}" target="_blank" rel="noopener noreferrer" class="chat-link">${linkText}</a>`;
|
|
428
|
-
}
|
|
429
|
-
);
|
|
430
|
-
|
|
431
|
-
// Handle numbered lists with descriptions (more complex pattern)
|
|
432
|
-
// Split into lines to process each line
|
|
433
|
-
const lines = html.split("\n");
|
|
434
|
-
const processedLines = [];
|
|
435
|
-
let inList = false;
|
|
436
|
-
|
|
437
|
-
for (let i = 0; i < lines.length; i++) {
|
|
438
|
-
const line = lines[i];
|
|
439
|
-
|
|
440
|
-
// Check if this is a numbered list item (starts with number and dot)
|
|
441
|
-
if (/^\d+\.\s+/.test(line)) {
|
|
442
|
-
if (!inList) {
|
|
443
|
-
processedLines.push('<ol class="chat-list">');
|
|
444
|
-
inList = true;
|
|
445
|
-
}
|
|
446
|
-
// Extract the content after the number
|
|
447
|
-
const content = line.replace(/^\d+\.\s+/, "");
|
|
448
|
-
processedLines.push(`<li>${content}`);
|
|
449
|
-
|
|
450
|
-
// Check if next line is indented (description)
|
|
451
|
-
if (i + 1 < lines.length && /^\s{2,}/.test(lines[i + 1])) {
|
|
452
|
-
i++; // Skip to next line
|
|
453
|
-
const description = lines[i].trim();
|
|
454
|
-
processedLines.push(
|
|
455
|
-
`<br><span class="chat-description">${description}</span></li>`
|
|
456
|
-
);
|
|
457
|
-
} else {
|
|
458
|
-
processedLines.push("</li>");
|
|
459
|
-
}
|
|
460
|
-
} else if (line.trim() === "" && inList) {
|
|
461
|
-
// Empty line might end the list
|
|
462
|
-
continue;
|
|
463
|
-
} else {
|
|
464
|
-
if (inList && line.trim() !== "") {
|
|
465
|
-
processedLines.push("</ol>");
|
|
466
|
-
inList = false;
|
|
467
|
-
}
|
|
468
|
-
if (line.trim() !== "") {
|
|
469
|
-
processedLines.push(line);
|
|
470
|
-
}
|
|
471
|
-
}
|
|
472
|
-
}
|
|
473
|
-
|
|
474
|
-
// Close any open list
|
|
475
|
-
if (inList) {
|
|
476
|
-
processedLines.push("</ol>");
|
|
477
|
-
}
|
|
478
|
-
|
|
479
|
-
html = processedLines.join("<br>");
|
|
480
|
-
|
|
481
|
-
// Clean up extra breaks
|
|
482
|
-
html = html.replace(/<br><br>/g, "<br>");
|
|
483
|
-
html = html.replace(/^<br>/, "");
|
|
484
|
-
|
|
485
|
-
// Convert **bold** to <strong>
|
|
486
|
-
html = html.replace(/\*\*([^*]+)\*\*/g, "<strong>$1</strong>");
|
|
487
|
-
|
|
488
|
-
// Convert *italic* to <em>
|
|
489
|
-
html = html.replace(/\*([^*]+)\*/g, "<em>$1</em>");
|
|
490
|
-
|
|
491
|
-
console.log("Processed HTML:", html);
|
|
492
|
-
|
|
493
|
-
return html;
|
|
494
|
-
}
|
|
495
|
-
|
|
496
|
-
private async getAssistantResponse(userMessage: string) {
|
|
497
|
-
try {
|
|
498
|
-
const response = await this.callChatAPI(userMessage);
|
|
499
|
-
// Convert markdown to HTML for rich content display
|
|
500
|
-
const htmlContent = this.parseMarkdownToHTML(response);
|
|
501
|
-
this.addMessage(htmlContent, "assistant", true); // true indicates HTML content
|
|
502
|
-
|
|
503
|
-
// Force a re-render after adding the message
|
|
504
|
-
setTimeout(() => {
|
|
505
|
-
this.renderHTMLMessages();
|
|
506
|
-
}, 100);
|
|
507
|
-
} catch (error) {
|
|
508
|
-
console.error("Error getting assistant response:", error);
|
|
509
|
-
this.addMessage(
|
|
510
|
-
"I apologize, but I encountered an error while processing your request. Please try again.",
|
|
511
|
-
"assistant"
|
|
512
|
-
);
|
|
513
|
-
} finally {
|
|
514
134
|
this.isAssistantTyping = false;
|
|
135
|
+
this.simulateAssistantResponse(userMessage);
|
|
136
|
+
}, 1000 + Math.random() * 2000);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
private simulateAssistantResponse(userMessage: string) {
|
|
140
|
+
// Simple response simulation - in a real implementation, this would call an API
|
|
141
|
+
let response = `I received your message: "${userMessage}". `;
|
|
142
|
+
|
|
143
|
+
if (userMessage.toLowerCase().includes("hello") || userMessage.toLowerCase().includes("hi")) {
|
|
144
|
+
response = "Hello! Nice to meet you. How can I assist you today?";
|
|
145
|
+
} else if (userMessage.toLowerCase().includes("help")) {
|
|
146
|
+
response = "I'm here to help! Feel free to ask me any questions about the documentation or topics you're interested in.";
|
|
147
|
+
} else if (userMessage.toLowerCase().includes("documentation") || userMessage.toLowerCase().includes("docs")) {
|
|
148
|
+
response = "I can help you navigate the documentation. What specific topic are you looking for?";
|
|
149
|
+
} else {
|
|
150
|
+
response = "That's an interesting question. Let me help you with that. Could you provide more details about what you're looking for?";
|
|
515
151
|
}
|
|
152
|
+
|
|
153
|
+
this.addMessage(response, "assistant");
|
|
516
154
|
}
|
|
517
155
|
|
|
518
156
|
formatTimestamp(timestamp: Date) {
|
|
519
|
-
return timestamp.toLocaleTimeString([], {
|
|
520
|
-
hour: "2-digit",
|
|
521
|
-
minute: "2-digit"
|
|
522
|
-
});
|
|
157
|
+
return timestamp.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
|
|
523
158
|
}
|
|
524
159
|
|
|
525
160
|
get sendButtonDisabled() {
|
|
526
161
|
return this.disabled || !this.currentMessage.trim();
|
|
527
162
|
}
|
|
528
|
-
|
|
529
|
-
handleCloseClick() {
|
|
530
|
-
this._isOpen = false;
|
|
531
|
-
this.updateBodyClass();
|
|
532
|
-
|
|
533
|
-
// Dispatch custom event to notify parent components
|
|
534
|
-
this.dispatchEvent(
|
|
535
|
-
new CustomEvent("chatclosed", {
|
|
536
|
-
detail: { closed: true }
|
|
537
|
-
})
|
|
538
|
-
);
|
|
539
|
-
}
|
|
540
|
-
|
|
541
|
-
handleClearClick() {
|
|
542
|
-
this.clearMessages();
|
|
543
|
-
|
|
544
|
-
// Dispatch custom event to notify parent components
|
|
545
|
-
this.dispatchEvent(
|
|
546
|
-
new CustomEvent("chatcleared", {
|
|
547
|
-
detail: { cleared: true }
|
|
548
|
-
})
|
|
549
|
-
);
|
|
550
|
-
}
|
|
551
|
-
|
|
552
|
-
handleOpenClick() {
|
|
553
|
-
try {
|
|
554
|
-
// Set flag to open chat after reload
|
|
555
|
-
localStorage.setItem(Chat.OPEN_STATE_KEY, "true");
|
|
556
|
-
} catch (error) {
|
|
557
|
-
console.warn("Failed to set open state in localStorage:", error);
|
|
558
|
-
}
|
|
559
|
-
// Hard reload the page to clear cache when opening chat
|
|
560
|
-
window.location.reload();
|
|
561
|
-
}
|
|
562
|
-
|
|
563
|
-
openChat() {
|
|
564
|
-
try {
|
|
565
|
-
// Set flag to open chat after reload
|
|
566
|
-
localStorage.setItem(Chat.OPEN_STATE_KEY, "true");
|
|
567
|
-
} catch (error) {
|
|
568
|
-
console.warn("Failed to set open state in localStorage:", error);
|
|
569
|
-
}
|
|
570
|
-
|
|
571
|
-
// Hard reload the page to clear cache when opening chat
|
|
572
|
-
window.location.reload();
|
|
573
|
-
}
|
|
574
|
-
|
|
575
|
-
closeChat() {
|
|
576
|
-
this._isOpen = false;
|
|
577
|
-
this.updateBodyClass();
|
|
578
|
-
|
|
579
|
-
// Dispatch custom event to notify parent components
|
|
580
|
-
this.dispatchEvent(
|
|
581
|
-
new CustomEvent("chatclosed", {
|
|
582
|
-
detail: { closed: true }
|
|
583
|
-
})
|
|
584
|
-
);
|
|
585
|
-
}
|
|
586
|
-
}
|
|
163
|
+
}
|
|
@@ -42,23 +42,23 @@
|
|
|
42
42
|
<slot name="doc-phase"></slot>
|
|
43
43
|
<slot name="version-banner"></slot>
|
|
44
44
|
<div class="content-body-container">
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
45
|
+
<div class="content-body">
|
|
46
|
+
<doc-breadcrumbs
|
|
47
|
+
lwc:if={showBreadcrumbs}
|
|
48
|
+
breadcrumbs={breadcrumbs}
|
|
49
|
+
></doc-breadcrumbs>
|
|
50
|
+
<slot onslotchange={onSlotChange}></slot>
|
|
51
|
+
<doc-sprig-survey
|
|
52
|
+
lwc:if={shouldDisplayFeedback}
|
|
53
|
+
></doc-sprig-survey>
|
|
54
|
+
</div>
|
|
55
|
+
<div lwc:if={showToc} class="right-nav-bar is-sticky">
|
|
56
|
+
<dx-toc
|
|
57
|
+
header={tocTitle}
|
|
58
|
+
options={tocOptions}
|
|
59
|
+
value={tocValue}
|
|
60
|
+
></dx-toc>
|
|
61
|
+
</div>
|
|
62
62
|
</div>
|
|
63
63
|
<div lwc:if={showFooter} class="footer-container">
|
|
64
64
|
<dx-footer variant="no-signup"></dx-footer>
|