Skip to content

Commit 6ab21db

Browse files
committed
Task 4801: chat history on docs
1 parent bcab49b commit 6ab21db

File tree

4 files changed

+112
-75
lines changed

4 files changed

+112
-75
lines changed

mkdocs_bs5/assets/css/style.css

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -596,6 +596,10 @@ table .table-light th {
596596
font-weight: 400;
597597
padding: 5px;
598598
}
599+
.bugster-hero .content .alert {
600+
font-size: 14px;
601+
padding: 10px;
602+
}
599603
.bugster-hero .col-md-6,
600604
.bugster-hero .col {
601605
padding: 0 5px;
@@ -624,6 +628,10 @@ table .table-light th {
624628
.bugster-chat .user-dialog {
625629
display: flex;
626630
justify-content: end;
631+
margin-top: 25px;
632+
}
633+
.bugster-chat .user-dialog:first-child {
634+
margin-top: 0px;
627635
}
628636
.bugster-chat .user-dialog-text {
629637
background: #2E3440;
@@ -640,6 +648,9 @@ table .table-light th {
640648
justify-content: start;
641649
margin-top: 25px;
642650
}
651+
.bugster-chat .bugster-dialog:last-of-type {
652+
min-height: 300px;
653+
}
643654
.bugster-chat .bugster-dialog-avatar {
644655
flex: 0 0 54px;
645656
margin-right: 15px;

mkdocs_bs5/assets/js/main-v2.js

Lines changed: 86 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -364,18 +364,19 @@ const escapeHtml = (unsafe) => {
364364
}
365365

366366
// Bugster
367+
let bugsterSessionId = null;
368+
367369
function Bugster() {
368370
if (!document.querySelector('#bugsterModal')) return;
369371

372+
let theQuestion = null;
373+
let chatMessages = [];
370374
const question = document.querySelector('#bugsterModal input#question');
371375
const bugsterChat = document.querySelector('#bugsterModal .bugster-chat');
372-
const bugsterChatFooter = document.querySelector('#bugsterModal .modal-footer');
373-
const bugsterChatFooterCollapse = new bootstrap.Collapse('#bugsterModal .modal-footer', { toggle: false });
374376
const userDialog = document.querySelector('.bugster-chat .user-dialog');
375377
const userText = document.querySelector('.bugster-chat .user-dialog-text');
376378
const bugsterDialog = document.querySelector('.bugster-chat .bugster-dialog');
377379
const bugsterText = document.querySelector('.bugster-chat .bugster-dialog-text .content');
378-
const askAnotherQuestion = document.querySelector('#ask-another-question');
379380
const md = new remarkable.Remarkable();
380381

381382
// Shortcut questions
@@ -391,118 +392,142 @@ function Bugster() {
391392
event.preventDefault();
392393

393394
if (question.value !== "") {
394-
userDialog.classList.add('d-none');
395-
bugsterDialog.classList.add('d-none');
395+
bugsterChat.classList.remove('d-none');
396+
theQuestion = question.value;
397+
question.value = "";
396398

397399
if (document.querySelector('.bugster-hero').checkVisibility() === false) {
398-
bugsterChatFooterCollapse.hide();
399-
bugsterChatFooter.addEventListener('hidden.bs.collapse', event => {
400-
setTimeout(() => {
401-
bugsterChat.classList.remove('d-none');
402-
userText.innerHTML = `<p>${ escapeHtml(question.value) }</p>`;
403-
userDialog.classList.remove('d-none');
404-
405-
setTimeout(function() {
406-
bugsterText.innerHTML = `<div class="spinner-grow spinner-grow-sm" role="status"></div>`;
407-
bugsterDialog.classList.remove('d-none');
408-
}, 500);
409-
410-
setTimeout(() => bugsterXHR(), 1500);
411-
}, 500);
412-
});
400+
prepareXHR();
413401
}
414402

415403
fadeOut(document.querySelector('.bugster-hero'), function() {
416-
bugsterChatFooterCollapse.hide();
417-
bugsterChatFooter.addEventListener('hidden.bs.collapse', event => {
418-
setTimeout(() => {
419-
bugsterChat.classList.remove('d-none');
420-
userText.innerHTML = `<p>${ escapeHtml(question.value) }</p>`;
421-
userDialog.classList.remove('d-none');
422-
423-
setTimeout(function() {
424-
bugsterText.innerHTML = `<div class="spinner-grow spinner-grow-sm" role="status"></div>`;
425-
bugsterDialog.classList.remove('d-none');
426-
}, 500);
427-
428-
setTimeout(() => bugsterXHR(), 1500);
429-
}, 500);
430-
});
404+
prepareXHR();
431405
});
432406
}
433407
});
434408

409+
const prepareXHR = () => {
410+
const userMsg = { sender: 'user', text: theQuestion };
411+
chatMessages.push(userMsg);
412+
renderMessage(userMsg);
413+
414+
const bugsterMsg = { sender: 'bugster', text: '', loading: true };
415+
chatMessages.push(bugsterMsg);
416+
renderMessage(bugsterMsg);
417+
418+
scrollBottom();
419+
420+
setTimeout(() => bugsterXHR(), 500);
421+
}
422+
435423
let isRequestInProgress = false;
436424

437425
const bugsterXHR = () => {
438426
if (isRequestInProgress) return;
439427

440428
isRequestInProgress = true;
429+
441430
const xhr = new XMLHttpRequest();
442431
xhr.open("POST", "https://bugster3.elmah.io/api/docs/ask", true);
443432
xhr.setRequestHeader("Content-Type", "application/json");
444433
xhr.setRequestHeader("Accept", "text/plain");
445434

446435
xhr.onprogress = function(progressEvent) {
447436
const { target } = progressEvent;
448-
if (bugsterText.innerHTML === '<div class="spinner-grow spinner-grow-sm" role="status"></div>') {
449-
bugsterText.innerHTML = '';
450-
}
451437
if (target.status === 200) {
452-
bugsterText.innerHTML = md.render(target.response);
438+
updateBugsterLastMessage(md.render(target.response));
453439
}
454440
};
455441

456442
xhr.onload = function() {
457443
if (xhr.status === 200) {
458-
// Same as in your `done` function in jQuery
459-
bugsterText.querySelectorAll('pre code').forEach(codeElement => {
444+
if (!bugsterSessionId) {
445+
bugsterSessionId = xhr.getResponseHeader("X-Bugster-SessionId");
446+
}
447+
448+
const lastBugsterMsg = bugsterChat.querySelectorAll('.bugster-dialog');
449+
const el = lastBugsterMsg[lastBugsterMsg.length - 1];
450+
451+
el.querySelectorAll('pre code').forEach(codeElement => {
460452
codeElement.parentNode.style.padding = "0px";
461453
hljs.highlightElement(codeElement);
462454
});
463455

464-
bugsterText.querySelectorAll('a').forEach(aElement => {
456+
el.querySelectorAll('a').forEach(aElement => {
465457
aElement.target = "_blank";
466458
aElement.rel = "noopener noreferrer";
467459
});
468460

469-
bugsterText.querySelectorAll('table').forEach(tableElement => {
461+
el.querySelectorAll('table').forEach(tableElement => {
470462
tableElement.classList.add('table');
471463
tableElement.querySelector('thead').classList.add('table-dark');
472464
});
473465

474-
askAnotherQuestion.classList.remove('d-none');
475-
476466
isRequestInProgress = false;
477467
}
478468
};
479469

480470
const payload = JSON.stringify({
481-
question: question.value,
482-
sessionId: "local"
471+
question: theQuestion,
472+
...(bugsterSessionId ? { sessionId: bugsterSessionId } : {})
483473
});
484474
xhr.send(payload);
485475
}
486476

487-
// Ask another question
488-
askAnotherQuestion.addEventListener('click', function() {
489-
askAnotherQuestion.classList.add('d-none');
490-
question.value = "";
491-
bugsterChatFooterCollapse.show();
492-
});
477+
const renderMessage = (msg) => {
478+
const messageEl = document.createElement('div');
479+
480+
if (msg.sender === 'user') {
481+
messageEl.className = 'user-dialog';
482+
messageEl.innerHTML = `<div class="user-dialog-text"><p>${msg.text}</p></div>`;
483+
} else {
484+
messageEl.className = 'bugster-dialog';
485+
messageEl.innerHTML = `<div class="bugster-dialog-avatar">
486+
<img class="img-fluid" src="assets/img/bugster.png" width="383" height="374" alt="Bugster">
487+
</div>
488+
<div class="bugster-dialog-text">
489+
<div class="content">
490+
<div class="spinner-grow spinner-grow-sm" role="status"></div>
491+
</div>
492+
</div>`;
493+
}
494+
495+
bugsterChat.appendChild(messageEl);
496+
}
497+
498+
const updateBugsterLastMessage = (text) => {
499+
const lastBugsterMsg = bugsterChat.querySelectorAll('.bugster-dialog');
500+
const el = lastBugsterMsg[lastBugsterMsg.length - 1];
501+
if (!el) return;
502+
503+
const msgText = el.querySelector('.bugster-dialog-text .content');
504+
msgText.innerHTML = text;
505+
}
493506

494507
// Reset modal when closed
495508
document.querySelector('#bugsterModal').addEventListener('hidden.bs.modal', () => {
496-
document.querySelector('.bugster-hero').removeAttribute('style');
497-
bugsterChatFooterCollapse.show();
498-
bugsterChat.classList.add('d-none');
499-
askAnotherQuestion.classList.add('d-none');
509+
theQuestion = null;
500510
question.value = "";
501-
userDialog.classList.add('d-none');
502-
userText.innerHTML = '';
503-
bugsterDialog.classList.add('d-none');
504-
bugsterText.innerHTML = '';
511+
512+
if (!bugsterSessionId) {
513+
document.querySelector('.bugster-hero').removeAttribute('style');
514+
bugsterChat.classList.add('d-none');
515+
userDialog.classList.add('d-none');
516+
userText.innerHTML = '';
517+
bugsterDialog.classList.add('d-none');
518+
bugsterText.innerHTML = '';
519+
}
520+
});
521+
522+
document.querySelector('#bugsterModal').addEventListener('show.bs.modal', () => {
523+
if (bugsterSessionId) {
524+
setTimeout(() => scrollBottom(), 200);
525+
}
505526
});
527+
528+
const scrollBottom = () => {
529+
document.querySelector('#bugsterModal .modal-body').scrollTop = bugsterChat.scrollHeight;
530+
}
506531
}
507532

508533
// FadeOut animation

mkdocs_bs5/assets/scss/style.scss

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -691,6 +691,11 @@ table .table-light th {
691691
font-weight: 400;
692692
padding: 5px;
693693
}
694+
695+
.alert {
696+
font-size: 14px;
697+
padding: 10px;
698+
}
694699
}
695700

696701
.col-md-6,
@@ -725,6 +730,11 @@ table .table-light th {
725730
.user-dialog {
726731
display: flex;
727732
justify-content: end;
733+
margin-top: 25px;
734+
735+
&:first-child {
736+
margin-top: 0px;
737+
}
728738
}
729739

730740
.user-dialog-text {
@@ -743,6 +753,10 @@ table .table-light th {
743753
display: flex;
744754
justify-content: start;
745755
margin-top: 25px;
756+
757+
&:last-of-type {
758+
min-height: 300px;
759+
}
746760
}
747761

748762
.bugster-dialog-avatar {

mkdocs_bs5/main.html

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -289,20 +289,7 @@
289289
</div>
290290
</div>
291291
</div>
292-
<div class="bugster-chat d-none">
293-
<div class="user-dialog d-none">
294-
<div class="user-dialog-text"></div>
295-
</div>
296-
<div class="bugster-dialog d-none">
297-
<div class="bugster-dialog-avatar">
298-
<img class="img-fluid" src="{{ 'assets/img/bugster.png'|url }}" width="383" height="374" alt="Bugster">
299-
</div>
300-
<div class="bugster-dialog-text">
301-
<div class="content"></div>
302-
<button id="ask-another-question" class="btn btn-primary d-none">Ask another question</button>
303-
</div>
304-
</div>
305-
</div>
292+
<div class="bugster-chat d-none"></div>
306293
</div>
307294
<div class="modal-footer collapse show">
308295
<form id="bugster-form" class="form w-100">

0 commit comments

Comments
 (0)