|
13 | 13 | Dropdown, |
14 | 14 | DropdownToggle, |
15 | 15 | DropdownMenu, |
16 | | - DropdownItem, |
17 | | - Input |
| 16 | + DropdownItem |
18 | 17 | } from '@sveltestrap/sveltestrap'; |
19 | 18 | import { |
20 | 19 | conversationStore, |
|
56 | 55 | import LoadingToComplete from '$lib/common/spinners/LoadingToComplete.svelte'; |
57 | 56 | import AudioSpeaker from '$lib/common/audio-player/AudioSpeaker.svelte'; |
58 | 57 | import CodeScript from '$lib/common/shared/CodeScript.svelte'; |
| 58 | + import Label from '$lib/common/shared/Label.svelte'; |
59 | 59 | import { realtimeChat } from '$lib/services/realtime-chat-service'; |
60 | 60 | import { webSpeech } from '$lib/services/web-speech'; |
61 | 61 | import LocalStorageManager from '$lib/helpers/utils/storage-manager'; |
|
64 | 64 | import { utcToLocal } from '$lib/helpers/datetime'; |
65 | 65 | import { replaceNewLine } from '$lib/helpers/http'; |
66 | 66 | import { isAudio, isExcel, isPdf } from '$lib/helpers/utils/file'; |
67 | | - import { ChatAction, ConversationTag, EditorType, FileSourceType, RichType, SenderAction, UserRole } from '$lib/helpers/enums'; |
| 67 | + import { ChatAction, EditorType, FileSourceType, RichType, SenderAction, UserRole } from '$lib/helpers/enums'; |
68 | 68 | import ChatTextArea from './chat-util/chat-text-area.svelte'; |
69 | 69 | import RichContent from './rich-content/rich-content.svelte'; |
70 | 70 | import RcMessage from "./rich-content/rc-message.svelte"; |
|
131 | 131 | /** @type {string[]} */ |
132 | 132 | let chatUtilOptions = []; |
133 | 133 | /** @type {string[]} */ |
134 | | - let selectedTags = []; |
| 134 | + let convTags = []; |
| 135 | + let newTagText = ''; |
135 | 136 |
|
136 | | - /** @type {import('$commonTypes').KeyValuePair[]} */ |
137 | | - let tagOptions = Object.entries(ConversationTag).map(([k, v]) => ( |
138 | | - { key: k, value: v } |
139 | | - )); |
140 | 137 | |
141 | 138 | /** @type {any[]} */ |
142 | 139 | let scrollbars = []; |
|
239 | 236 | conversation = await getConversation(params.conversationId, true); |
240 | 237 | dialogs = await getDialogs(params.conversationId, dialogCount); |
241 | 238 | conversationUser = conversation?.user; |
242 | | - selectedTags = conversation?.tags || []; |
| 239 | + convTags = conversation?.tags || []; |
| 240 | +
|
243 | 241 | latestStateLog = conversation?.states; |
244 | 242 | initUserSentMessages(dialogs); |
245 | 243 | initChatView(); |
|
1409 | 1407 | function toggleTagModal() { |
1410 | 1408 | isOpenTagModal = !isOpenTagModal; |
1411 | 1409 | if (!isOpenTagModal) { |
1412 | | - selectedTags = conversation?.tags || []; |
| 1410 | + newTagText = ''; |
| 1411 | + convTags = conversation?.tags || []; |
1413 | 1412 | } |
1414 | 1413 | } |
1415 | 1414 |
|
1416 | | - /** |
1417 | | - * @param {any} e |
1418 | | - * @param {string} value |
1419 | | - */ |
1420 | | - function changeTagSelection(e, value) { |
1421 | | - const checked = e.target.checked; |
1422 | | - if (checked) { |
1423 | | - selectedTags = [...new Set([...selectedTags, value])]; |
1424 | | - } else { |
1425 | | - selectedTags = selectedTags.filter(x => x !== value); |
| 1415 | + /** @param {number | string} idx */ |
| 1416 | + function removeTag(idx) { |
| 1417 | + const tag = convTags?.[/** @type {number} */ (idx)]; |
| 1418 | + if (!tag) return; |
| 1419 | + convTags = convTags.filter(t => t !== tag); |
| 1420 | + } |
| 1421 | +
|
| 1422 | + function addTag() { |
| 1423 | + const tag = _.trim(newTagText); |
| 1424 | + if (!tag || convTags.includes(tag)) { |
| 1425 | + return; |
1426 | 1426 | } |
| 1427 | + convTags = [...convTags, tag]; |
| 1428 | + newTagText = ''; |
1427 | 1429 | } |
1428 | 1430 |
|
1429 | 1431 | function updateChatTags() { |
| 1432 | + const originalTags = conversation?.tags || []; |
| 1433 | + const toAddTags = convTags.filter(t => !originalTags.includes(t)); |
| 1434 | + const toDeleteTags = originalTags.filter((/** @type {string} */ t) => !convTags.includes(t)); |
| 1435 | +
|
| 1436 | + if (toAddTags.length === 0 && toDeleteTags.length === 0) { |
| 1437 | + isOpenTagModal = false; |
| 1438 | + return; |
| 1439 | + } |
| 1440 | +
|
1430 | 1441 | isLoading = true; |
1431 | 1442 | updateConversationTags( |
1432 | 1443 | params.conversationId, |
1433 | | - { |
1434 | | - toAddTags: selectedTags, |
1435 | | - toDeleteTags: tagOptions.filter(x => !selectedTags.includes(x.value)).map(x => x.value) |
1436 | | - }) |
| 1444 | + { toAddTags, toDeleteTags }) |
1437 | 1445 | .then(res => { |
1438 | 1446 | if (res) { |
| 1447 | + conversation.tags = [...convTags]; |
1439 | 1448 | isComplete = true; |
1440 | | - successText = "Tags has been updated!"; |
| 1449 | + successText = "Tags have been updated!"; |
1441 | 1450 | setTimeout(() => { |
1442 | 1451 | isComplete = false; |
1443 | 1452 | successText = ""; |
1444 | 1453 | }, duration); |
1445 | 1454 | } else { |
1446 | | - throw "Failed to update chat tags."; |
| 1455 | + throw "Failed to update tags."; |
1447 | 1456 | } |
1448 | 1457 | }).catch(() => { |
1449 | | - selectedTags = conversation?.tags || []; |
| 1458 | + convTags = conversation?.tags || []; |
1450 | 1459 | isError = true; |
1451 | 1460 | errorText = "Failed to update tags!"; |
1452 | 1461 | setTimeout(() => { |
|
1567 | 1576 | closeable |
1568 | 1577 | toggleModal={() => toggleTagModal()} |
1569 | 1578 | confirmBtnText={'Confirm'} |
1570 | | - cancelBtnText={'Cancel'} |
| 1579 | + cancelBtnText={''} |
1571 | 1580 | confirm={() => updateChatTags()} |
1572 | | - cancel={() => toggleTagModal()} |
1573 | 1581 | close={() => toggleTagModal()} |
1574 | 1582 | > |
1575 | 1583 | <div class="conv-tags-container"> |
1576 | | - {#each tagOptions as op} |
1577 | | - <div class="conv-tag-unit"> |
1578 | | - <Input |
1579 | | - type="checkbox" |
1580 | | - label={op.value} |
1581 | | - checked={selectedTags.includes(op.value)} |
1582 | | - on:change={e => changeTagSelection(e, op.value)} |
1583 | | - /> |
1584 | | - </div> |
| 1584 | + {#each convTags as tag, idx} |
| 1585 | + <Label |
| 1586 | + text={tag} |
| 1587 | + index={idx} |
| 1588 | + color="info" |
| 1589 | + ellipsis |
| 1590 | + onClose={removeTag} |
| 1591 | + /> |
1585 | 1592 | {/each} |
1586 | 1593 | </div> |
| 1594 | + <div class="conv-tag-add"> |
| 1595 | + <input |
| 1596 | + class="form-control form-control-sm" |
| 1597 | + type="text" |
| 1598 | + placeholder="Enter new tag..." |
| 1599 | + maxlength={50} |
| 1600 | + bind:value={newTagText} |
| 1601 | + on:keydown={e => { if (e.key === 'Enter') addTag(); }} |
| 1602 | + /> |
| 1603 | + <button |
| 1604 | + class="btn btn-primary btn-sm" |
| 1605 | + disabled={!_.trim(newTagText)} |
| 1606 | + on:click={() => addTag()} |
| 1607 | + > |
| 1608 | + <i class="bx bx-plus" /> |
| 1609 | + </button> |
| 1610 | + </div> |
1587 | 1611 | </DialogModal> |
1588 | 1612 |
|
1589 | 1613 | <DialogModal |
|
1763 | 1787 | disabled={disableAction} |
1764 | 1788 | on:click={() => toggleTagModal()} |
1765 | 1789 | > |
1766 | | - Add Tags |
| 1790 | + Tags |
1767 | 1791 | </DropdownItem> |
1768 | 1792 | {/if} |
1769 | 1793 | {#if agent?.id === LEARNER_AGENT_ID && mode === TRAINING_MODE} |
|
0 commit comments