Skip to content

Commit 0b564fc

Browse files
authored
Merge pull request #34 from iceljc/features/add-conversation-truncate
Features/add conversation truncate
2 parents 2f5234f + c4872cd commit 0b564fc

File tree

6 files changed

+143
-35
lines changed

6 files changed

+143
-35
lines changed

src/app.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
<head>
44
<meta charset="utf-8" />
55
<!--<link rel="icon" href="%sveltekit.assets%/icons/favicon.ico" />-->
6-
<meta name="viewport" content="width=device-width, initial-scale=1" />
6+
<meta name="viewport" content="width=device-width, initial-scale=1 maximum-scale=1" />
77
%sveltekit.head%
88
</head>
99
<body data-sveltekit-preload-data="hover">

src/lib/helpers/http.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ axios.interceptors.request.use(
77
// Add your authentication logic here
88
let user = getUserStore();
99
setGlobalLoad(true);
10-
let headers = axios.defaults.headers;
1110
// For example, attach an authentication token to the request headers
1211
config.headers.Authorization = `Bearer ${user.token}`;
1312
return config;

src/lib/scss/custom/pages/_chat.scss

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,7 @@
164164
.dropdown-toggle {
165165
font-size: 18px;
166166
padding: 4px;
167+
cursor: pointer;
167168
color: var(--#{$prefix}secondary-color);
168169
@media (max-width: 575.98px) {
169170
display: none;

src/lib/services/api-endpoints.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ export const endpoints = {
3737
conversationDeletionUrl: `${host}/conversation/{conversationId}`,
3838
conversationDetailUrl: `${host}/conversation/{conversationId}`,
3939
dialogsUrl: `${host}/conversation/{conversationId}/dialogs`,
40+
conversationMessageDeletionUrl: `${host}/conversation/{conversationId}/message/{messageId}`,
4041

4142
// LLM provider
4243
llmProvidersUrl: `${host}/llm-providers`,

src/lib/services/conversation-service.js

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -65,13 +65,30 @@ export async function GetDialogs(conversationId) {
6565
* @param {string} agentId The agent id
6666
* @param {string} conversationId The conversation id
6767
* @param {string} message The text message sent to CSR
68+
* @param {string} truncateMsgId The message id to be deleted
6869
*/
69-
export async function sendMessageToHub(agentId, conversationId, message) {
70+
export async function sendMessageToHub(agentId, conversationId, message, truncateMsgId = '') {
7071
let url = replaceUrl(endpoints.conversationMessageUrl, {
7172
agentId: agentId,
72-
conversationId: conversationId});
73+
conversationId: conversationId
74+
});
7375
const response = await axios.post(url, {
74-
"text": message
76+
text: message,
77+
truncateMessageId: truncateMsgId,
7578
});
7679
return response.data;
7780
}
81+
82+
/**
83+
* delete a message in conversation
84+
* @param {string} conversationId The conversation id
85+
* @param {string} messageId The text message sent to CSR
86+
*/
87+
export async function deleteConversationMessage(conversationId, messageId) {
88+
let url = replaceUrl(endpoints.conversationMessageDeletionUrl, {
89+
conversationId: conversationId,
90+
messageId: messageId
91+
});
92+
const response = await axios.delete(url);
93+
return response.data;
94+
}

src/routes/chat/[agentId]/[conversationId]/chat-box.svelte

Lines changed: 120 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,11 @@
44
DropdownToggle,
55
DropdownMenu,
66
DropdownItem,
7+
Modal,
8+
ModalHeader,
9+
ModalBody,
10+
ModalFooter,
11+
Button
712
} from '@sveltestrap/sveltestrap';
813
import 'overlayscrollbars/overlayscrollbars.css';
914
import { OverlayScrollbars } from 'overlayscrollbars';
@@ -12,7 +17,7 @@
1217
import Link from 'svelte-link';
1318
import { signalr } from '$lib/services/signalr-service.js';
1419
import { webSpeech } from '$lib/services/web-speech.js';
15-
import { sendMessageToHub, GetDialogs } from '$lib/services/conversation-service.js';
20+
import { sendMessageToHub, GetDialogs, deleteConversationMessage } from '$lib/services/conversation-service.js';
1621
import { newConversation } from '$lib/services/conversation-service';
1722
import { conversationStore } from '$lib/helpers/store.js';
1823
import { utcToLocal } from '$lib/helpers/datetime';
@@ -40,7 +45,10 @@
4045
};
4146
const params = $page.params;
4247
48+
/** @type {string} */
4349
let text = "";
50+
let editText = "";
51+
let truncateMsgId = "";
4452
4553
/** @type {import('$types').AgentModel} */
4654
export let agent;
@@ -62,8 +70,9 @@
6270
let stateLogs = [];
6371
6472
/** @type {boolean} */
65-
let isLoadLog = false;
66-
let isLoadStates = false;
73+
let isLoadContentLog = false;
74+
let isLoadStateLog = false;
75+
let isShowEditMsgModal = false;
6776
6877
onMount(async () => {
6978
dialogs = await GetDialogs(params.conversationId);
@@ -164,48 +173,129 @@
164173
165174
function endChat() {
166175
if (window.location === window.parent.location) {
176+
// @ts-ignore
177+
Swal.fire({
178+
title: 'Are you sure?',
179+
text: "You will exit this conversation.",
180+
icon: 'warning',
181+
customClass: 'delete-modal',
182+
showCancelButton: true,
183+
confirmButtonText: 'Yes',
184+
cancelButtonText: 'No'
185+
// @ts-ignore
186+
}).then((result) => {
187+
if (result.value) {
188+
window.close();
189+
}
190+
});
191+
} else {
192+
window.parent.postMessage({ action: "close" }, "*");
193+
}
194+
}
195+
196+
function toggleContentLog() {
197+
isLoadContentLog = !isLoadContentLog;
198+
}
199+
200+
function toggleStateLog() {
201+
isLoadStateLog = !isLoadStateLog;
202+
}
203+
204+
/**
205+
* @param {any} e
206+
* @param {string} messageText
207+
*/
208+
function copyMessage(e, messageText) {
209+
e.preventDefault();
210+
if (!!!text) {
211+
text += messageText;
212+
} else {
213+
text += ' ' + messageText;
214+
}
215+
}
216+
217+
/**
218+
* @param {any} e
219+
* @param {string} messageId
220+
*/
221+
function deleteMessage(e, messageId) {
222+
e.preventDefault();
223+
167224
// @ts-ignore
168225
Swal.fire({
169226
title: 'Are you sure?',
170-
text: "You will exit this conversation.",
227+
text: "You won't be able to revert this!",
171228
icon: 'warning',
172229
customClass: 'delete-modal',
173230
showCancelButton: true,
174-
confirmButtonText: 'Yes',
231+
confirmButtonText: 'Yes, delete it!',
175232
cancelButtonText: 'No'
176233
// @ts-ignore
177-
}).then((result) => {
234+
}).then(async (result) => {
178235
if (result.value) {
179-
window.close();
236+
await handleDeleteMessage(messageId);
180237
}
181238
});
182-
} else {
183-
window.parent.postMessage({ action: "close" }, "*");
184-
}
185239
}
186240
187-
function viewContentLog() {
188-
isLoadLog = true;
189-
}
241+
/** @param {string} messageId */
242+
async function handleDeleteMessage(messageId) {
243+
const isDeleted = truncateDialog(messageId);
244+
if (!isDeleted) return;
245+
await deleteConversationMessage(params.conversationId, messageId);
246+
}
190247
191-
function viewStateLog() {
192-
isLoadStates = true;
248+
/**
249+
* @param {any} e
250+
* @param {import('$types').ChatResponseModel} message
251+
*/
252+
function editMessage(e, message) {
253+
e.preventDefault();
254+
truncateMsgId = message?.message_id;
255+
editText = message?.text;
256+
isShowEditMsgModal = true;
193257
}
194258
195-
function closeContentLog() {
196-
isLoadLog = false;
259+
function toggleEditMsgModel() {
260+
isShowEditMsgModal = !isShowEditMsgModal;
261+
if (!isShowEditMsgModal) {
262+
truncateMsgId = "";
263+
editText = "";
264+
}
197265
}
198266
199-
function closeStateLog() {
200-
isLoadStates = false;
267+
async function confirmEditMsg() {
268+
const isDeleted = truncateDialog(truncateMsgId);
269+
if (!isDeleted) return;
270+
toggleEditMsgModel();
271+
await sendMessageToHub(params.agentId, params.conversationId, editText, truncateMsgId);
272+
}
273+
274+
/** @param {string} messageId */
275+
function truncateDialog(messageId) {
276+
const foundIdx = dialogs.findIndex(x => x.message_id === messageId);
277+
if (foundIdx < 0) return false;
278+
dialogs = dialogs.filter((x, idx) => idx < foundIdx);
279+
return true;
201280
}
202281
</script>
203282
283+
<Modal class="delete-modal" fade size='xl' isOpen={isShowEditMsgModal} toggle={toggleEditMsgModel}>
284+
<ModalHeader>Edit message</ModalHeader>
285+
<ModalBody>
286+
<textarea class="form-control chat-input" rows="10" maxlength={500} bind:value={editText} placeholder="Enter Message..." />
287+
</ModalBody>
288+
<ModalFooter>
289+
<Button color="primary" on:click={confirmEditMsg} disabled={!!!_.trim(editText)}>Confirm</Button>
290+
<Button color="secondary" on:click={toggleEditMsgModel}>Cancel</Button>
291+
</ModalFooter>
292+
</Modal>
293+
204294
<div class="d-lg-flex">
205295
<Splitpanes>
206-
{#if isLoadStates}
296+
{#if isLoadStateLog}
207297
<Pane size={30} minSize={20} maxSize={50} >
208-
<StateLog stateLogs={stateLogs} closeWindow={closeStateLog} />
298+
<StateLog stateLogs={stateLogs} closeWindow={toggleStateLog} />
209299
</Pane>
210300
{/if}
211301
<Pane minSize={20}>
@@ -229,11 +319,11 @@
229319
<i class="bx bx-dots-horizontal-rounded" />
230320
</DropdownToggle>
231321
<DropdownMenu class="dropdown-menu-end">
232-
{#if !isLoadLog}
233-
<DropdownItem on:click={() => viewContentLog()}>View Log</DropdownItem>
322+
{#if !isLoadContentLog}
323+
<DropdownItem on:click={() => toggleContentLog()}>View Log</DropdownItem>
234324
{/if}
235-
{#if !isLoadStates}
236-
<DropdownItem on:click={() => viewStateLog()}>View States</DropdownItem>
325+
{#if !isLoadStateLog}
326+
<DropdownItem on:click={() => toggleStateLog()}>View States</DropdownItem>
237327
{/if}
238328
<DropdownItem on:click={newConversationHandler}>New Conversation</DropdownItem>
239329
</DropdownMenu>
@@ -270,9 +360,9 @@
270360
<i class="bx bx-dots-vertical-rounded" />
271361
</DropdownToggle>
272362
<DropdownMenu class="dropdown-menu-end">
273-
<DropdownItem href="#">Edit</DropdownItem>
274-
<DropdownItem href="#">Copy</DropdownItem>
275-
<DropdownItem href="#">Delete</DropdownItem>
363+
<DropdownItem on:click={(e) => editMessage(e, message)}>Edit</DropdownItem>
364+
<DropdownItem on:click={(e) => copyMessage(e, message.text)}>Copy</DropdownItem>
365+
<DropdownItem on:click={(e) => deleteMessage(e, message.message_id)}>Delete</DropdownItem>
276366
</DropdownMenu>
277367
</Dropdown>
278368
{:else}
@@ -355,9 +445,9 @@
355445
</div>
356446
</div>
357447
</Pane>
358-
{#if isLoadLog}
448+
{#if isLoadContentLog}
359449
<Pane size={30} minSize={20} maxSize={50}>
360-
<ContentLog logs={contentLogs} closeWindow={closeContentLog} />
450+
<ContentLog logs={contentLogs} closeWindow={toggleContentLog} />
361451
</Pane>
362452
{/if}
363453
</Splitpanes>

0 commit comments

Comments
 (0)