From 321517146363f18b6c2635059d82b8739698159f Mon Sep 17 00:00:00 2001
From: Jicheng Lu <103353@smsassist.com>
Date: Wed, 25 Sep 2024 16:18:53 -0500
Subject: [PATCH 1/2] add multiselect, add chat event
---
src/lib/common/LiveChatEntry.svelte | 30 +-
src/lib/common/MultiSelect.svelte | 310 ++++++++++++++++++
src/lib/helpers/constants.js | 2 +
src/lib/helpers/store.js | 13 +
src/lib/helpers/types/conversationTypes.js | 14 +-
src/lib/helpers/utils/chat.js | 37 +++
src/lib/scss/app.scss | 1 +
.../scss/custom/components/_multiselect.scss | 95 ++++++
src/lib/services/conversation-service.js | 1 -
.../[agentId]/[conversationId]/+page.svelte | 2 +-
.../[conversationId]/chat-box.svelte | 25 +-
.../rich-content/rich-content.svelte | 1 -
src/routes/page/conversation/+page.svelte | 1 +
src/routes/page/plugin/plugin-list.svelte | 29 +-
14 files changed, 529 insertions(+), 32 deletions(-)
create mode 100644 src/lib/common/MultiSelect.svelte
create mode 100644 src/lib/helpers/utils/chat.js
create mode 100644 src/lib/scss/custom/components/_multiselect.scss
diff --git a/src/lib/common/LiveChatEntry.svelte b/src/lib/common/LiveChatEntry.svelte
index 755e41be..5450cc55 100644
--- a/src/lib/common/LiveChatEntry.svelte
+++ b/src/lib/common/LiveChatEntry.svelte
@@ -3,49 +3,49 @@
import { onMount } from 'svelte';
import { PUBLIC_LIVECHAT_HOST, PUBLIC_LIVECHAT_ENTRY_ICON } from '$env/static/public';
import { getSettingDetail } from '$lib/services/setting-service';
+ import { chatBotStore } from '$lib/helpers/store';
+ import { CHAT_FRAME_ID } from '$lib/helpers/constants';
- let showChatIcon = false;
- let showChatBox = false;
let chatUrl = PUBLIC_LIVECHAT_HOST;
onMount(async () => {
const agentSettings = await getSettingDetail("Agent");
chatUrl = `${PUBLIC_LIVECHAT_HOST}chat/${agentSettings.hostAgentId}?isFrame=true`;
- showChatIcon = true;
});
// Handle event from iframe
window.onmessage = async function(e) {
if (e.data.action == 'close') {
- showChatIcon = true;
- showChatBox = false;
+ chatBotStore.set({
+ showChatBox: false
+ });
}
};
- function handleChatBox() {
- showChatIcon = false;
- showChatBox = true;
+ function openChatBox() {
+ chatBotStore.set({
+ showChatBox: true
+ });
}
- {#if showChatBox}
+ {#if $chatBotStore.showChatBox}
+ id={CHAT_FRAME_ID}
+ />
{/if}
- {#if showChatIcon}
+ {#if !$chatBotStore.showChatBox}
-
diff --git a/src/lib/common/MultiSelect.svelte b/src/lib/common/MultiSelect.svelte
new file mode 100644
index 00000000..10a707c7
--- /dev/null
+++ b/src/lib/common/MultiSelect.svelte
@@ -0,0 +1,310 @@
+
+
+
+
handleClickOutside(e)}
+>
+
+
+
+ {#if showOptionList}
+
innerScroll()}>
+
+
+
+
+
changeSearchValue(e)}
+ />
+
+ {#if innerOptions.length > 0}
+ {#if selectAll}
+ -
+
+ checkSelectAll(e)}
+ />
+
+
+ {'Select all'}
+
+
+ {/if}
+ {#each innerOptions as option, idx (idx)}
+ -
+
+ checkOption(e, option)}
+ />
+
+
+ {option.name}
+
+
+ {/each}
+ {:else}
+ -
+
Nothing...
+
+ {/if}
+
+ {/if}
+
\ No newline at end of file
diff --git a/src/lib/helpers/constants.js b/src/lib/helpers/constants.js
index eb675123..d85ffe1f 100644
--- a/src/lib/helpers/constants.js
+++ b/src/lib/helpers/constants.js
@@ -1,5 +1,7 @@
import { EditorType, UserRole } from "./enums";
+export const CHAT_FRAME_ID = "chatbox-frame";
+
export const USER_SENDERS = [
UserRole.Admin,
UserRole.User,
diff --git a/src/lib/helpers/store.js b/src/lib/helpers/store.js
index 5aa79dec..eecead98 100644
--- a/src/lib/helpers/store.js
+++ b/src/lib/helpers/store.js
@@ -182,6 +182,19 @@ const createKnowledgeBaseDocumentStore = () => {
export const knowledgeBaseDocumentStore = createKnowledgeBaseDocumentStore();
+const createChatBotStore = () => {
+ const { subscribe, set, update } = writable({ showChatBox: false });
+
+ return {
+ set,
+ update,
+ subscribe
+ }
+};
+
+export const chatBotStore = createChatBotStore();
+
+
export function resetLocalStorage(resetUser = false) {
conversationUserStateStore.resetAll();
conversationSearchOptionStore.reset();
diff --git a/src/lib/helpers/types/conversationTypes.js b/src/lib/helpers/types/conversationTypes.js
index 52027e6e..94212cf3 100644
--- a/src/lib/helpers/types/conversationTypes.js
+++ b/src/lib/helpers/types/conversationTypes.js
@@ -182,6 +182,14 @@ IRichContent.prototype.quick_replies;
* @property {Date} created_at - The log sent time.
*/
+/**
+ * Conversation states
+ * @typedef {Object} ConversationStateModel
+ * @property {string} key - The state key.
+ * @property {string} value - The state value.
+ * @property {number} [active_rounds] - The state active rounds.
+ */
+
/**
* Conversation states added by user
*
@@ -221,9 +229,9 @@ IRichContent.prototype.quick_replies;
* Conversation postback
*
* @typedef {Object} Postback
- * @property {string?} functionName - The function name.
+ * @property {string?} [functionName] - The function name.
* @property {string?} payload - The payload.
- * @property {string?} parentId - The parent message id.
+ * @property {string?} [parentId] - The parent message id.
*/
/**
@@ -232,7 +240,7 @@ IRichContent.prototype.quick_replies;
* @typedef {Object} MessageData
* @property {string?} [truncateMsgId] - The truncated message.
* @property {string?} [inputMessageId] - The input message.
- * @property {string[]?} [states] - The states input by user.
+ * @property {ConversationStateModel[]?} [states] - The states input by user.
* @property {Postback?} [postback] - The parent message id.
* @property {string?} [payload] - The payload message.
*/
diff --git a/src/lib/helpers/utils/chat.js b/src/lib/helpers/utils/chat.js
new file mode 100644
index 00000000..4dc3eb3a
--- /dev/null
+++ b/src/lib/helpers/utils/chat.js
@@ -0,0 +1,37 @@
+/**
+ * @param {string} chatFrameId
+ * @param {string} text
+ * @param {import('$conversationTypes').MessageData | null} data
+ */
+export function sendToChatBot(chatFrameId, text, data = null) {
+ const chatFrame = document.getElementById(chatFrameId);
+ const content = { action: "chat", text: text, data: data };
+
+ if (chatFrame) {
+ // @ts-ignore
+ chatFrame.contentWindow.postMessage(content, "*");
+ }
+}
+
+/**
+ * @param {() => void} func
+ */
+export function addChatBoxMountEventListener(func) {
+ window.addEventListener("message", e => {
+ if (e.data.event === 'chat-box-mounted') {
+ func();
+ }
+ });
+}
+
+/**
+ * @param {string} chatFrameId
+ * @param {string} text
+ */
+export function loadChatFrame(chatFrameId, text) {
+ const chatFrame = document.getElementById(chatFrameId);
+ if (chatFrame) {
+ // @ts-ignore
+ chatFrame.contentWindow.postMessage({ action: "chat", text: text }, "*");
+ }
+}
\ No newline at end of file
diff --git a/src/lib/scss/app.scss b/src/lib/scss/app.scss
index eb3cabb8..78f25531 100644
--- a/src/lib/scss/app.scss
+++ b/src/lib/scss/app.scss
@@ -43,6 +43,7 @@ File: Main Css File
@import "custom/components/file";
@import "custom/components/audio";
@import "custom/components/text";
+@import "custom/components/multiselect";
// Plugins
@import "custom/plugins/custom-scrollbar";
diff --git a/src/lib/scss/custom/components/_multiselect.scss b/src/lib/scss/custom/components/_multiselect.scss
new file mode 100644
index 00000000..2883f678
--- /dev/null
+++ b/src/lib/scss/custom/components/_multiselect.scss
@@ -0,0 +1,95 @@
+.multiselect-container {
+ position: relative;
+
+ .display-container {
+ .display-suffix {
+ position: absolute;
+ right: 0.6rem;
+ top: 0.18rem;
+ font-size: 1.5rem;
+
+ i {
+ transition: all .2s ease-in-out;
+ }
+ }
+
+ input[type='text'] {
+ padding-right: 1.5rem;
+ }
+
+ .show-list {
+ i {
+ transform: rotate(180deg);
+ }
+ }
+ }
+
+ .option-list {
+ padding: 5px 2px;
+ border: 2px solid var(--bs-border-color-translucent);
+ border-radius: 5px;
+
+ overflow-x: auto;
+ overflow-y: auto;
+ scrollbar-width: thin;
+ max-height: 230px;
+
+ position: absolute;
+ left: 0px;
+ right: 0px;
+ z-index: 99;
+ background-color: white;
+
+ .search-box {
+ padding: 5px 10px;
+
+ input[type='text'] {
+ padding: 5px 1.5rem;
+ border-radius: 5px;
+ position: relative;
+ }
+ }
+
+ .search-prefix {
+ position: absolute;
+ z-index: 100;
+ left: 1.2rem;
+ top: 1.2rem;
+ display: flex;
+ }
+ }
+
+ ul {
+ list-style: none;
+ padding-left: 0px;
+ margin-bottom: 0px;
+
+ .option-item {
+ display: flex;
+ gap: 3px;
+ padding: 5px 10px;
+
+ .select-box {
+ flex: 0 0 10%;
+ max-width: 20px;
+ }
+
+ .select-name {
+ flex: 0 0 90%;
+ max-width: 300px;
+ font-size: 1.1em;
+ word-break: break-all;
+ }
+
+ input[type='checkbox'] {
+ outline: none !important;
+ box-shadow: none !important;
+ font-size: 1.1em;
+ }
+
+ .nothing {
+ padding-left: 10px;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/lib/services/conversation-service.js b/src/lib/services/conversation-service.js
index 04bc25a1..718e4abc 100644
--- a/src/lib/services/conversation-service.js
+++ b/src/lib/services/conversation-service.js
@@ -90,7 +90,6 @@ export async function GetDialogs(conversationId) {
* @param {import('$conversationTypes').MessageData?} data - Additional data
*/
export async function sendMessageToHub(agentId, conversationId, text, data = null) {
- console.log(data);
let url = replaceUrl(endpoints.conversationMessageUrl, {
agentId: agentId,
conversationId: conversationId
diff --git a/src/routes/chat/[agentId]/[conversationId]/+page.svelte b/src/routes/chat/[agentId]/[conversationId]/+page.svelte
index 463faa27..b42bae56 100644
--- a/src/routes/chat/[agentId]/[conversationId]/+page.svelte
+++ b/src/routes/chat/[agentId]/[conversationId]/+page.svelte
@@ -23,5 +23,5 @@
{#if currentUser}
-
+
{/if}
\ No newline at end of file
diff --git a/src/routes/chat/[agentId]/[conversationId]/chat-box.svelte b/src/routes/chat/[agentId]/[conversationId]/chat-box.svelte
index 41bd052f..38911b30 100644
--- a/src/routes/chat/[agentId]/[conversationId]/chat-box.svelte
+++ b/src/routes/chat/[agentId]/[conversationId]/chat-box.svelte
@@ -167,12 +167,6 @@
});
onMount(async () => {
- window.addEventListener('message', e => {
- if (e.data.action === 'logout') {
- resetLocalStorage(true);
- }
- });
-
autoScrollLog = true;
dialogs = await GetDialogs(params.conversationId);
conversationUser = await getConversationUser(params.conversationId);
@@ -195,6 +189,18 @@
].filter(Boolean);
refresh();
autoScrollLog = false;
+
+ window.addEventListener('message', e => {
+ if (e.data.action === 'logout') {
+ resetLocalStorage(true);
+ }
+
+ if (e.data.action === 'chat' && !isThinking && !isSendingMsg) {
+ sendChatMessage(e.data.text, e.data.data || null);
+ }
+ });
+
+ // window.parent.postMessage({ event: "chat-box-mounted" }, "*");
});
function resizeChatWindow() {
@@ -441,7 +447,12 @@
autoScrollLog = true;
clearInstantLogs();
renewUserSentMessages(msgText);
- const postback = buildPostbackMessage(dialogs, data?.payload || msgText, data?.truncateMsgId);
+
+ let postback = data?.postback;
+ if (!postback) {
+ postback = buildPostbackMessage(dialogs, data?.payload || msgText, data?.truncateMsgId);
+ }
+
/** @type {import('$conversationTypes').MessageData?} */
let messageData = {
...data,
diff --git a/src/routes/chat/[agentId]/[conversationId]/rich-content/rich-content.svelte b/src/routes/chat/[agentId]/[conversationId]/rich-content/rich-content.svelte
index f974bcbc..85a795e0 100644
--- a/src/routes/chat/[agentId]/[conversationId]/rich-content/rich-content.svelte
+++ b/src/routes/chat/[agentId]/[conversationId]/rich-content/rich-content.svelte
@@ -23,7 +23,6 @@
$: {
const richType = message?.rich_content?.message?.rich_type;
- console.log(message);
if (richType === RichType.QuickReply) {
options = message?.rich_content?.message?.quick_replies;
diff --git a/src/routes/page/conversation/+page.svelte b/src/routes/page/conversation/+page.svelte
index 1fb4139a..122d8020 100644
--- a/src/routes/page/conversation/+page.svelte
+++ b/src/routes/page/conversation/+page.svelte
@@ -26,6 +26,7 @@
import { utcToLocal } from '$lib/helpers/datetime';
import Swal from 'sweetalert2';
import lodash from "lodash";
+ import MultiSelect from '$lib/common/MultiSelect.svelte';
let isLoading = false;
let isComplete = false;
diff --git a/src/routes/page/plugin/plugin-list.svelte b/src/routes/page/plugin/plugin-list.svelte
index 78c39778..097917bb 100644
--- a/src/routes/page/plugin/plugin-list.svelte
+++ b/src/routes/page/plugin/plugin-list.svelte
@@ -9,6 +9,9 @@
} from '@sveltestrap/sveltestrap';
import { installPlugin, removePlugin } from '$lib/services/plugin-service';
import Swal from 'sweetalert2';
+ import { sendToChatBot } from '$lib/helpers/utils/chat';
+
+ import { CHAT_FRAME_ID } from '$lib/helpers/constants';
/** @type {import('$pluginTypes').PluginDefModel[]} */
export let plugins;
@@ -45,6 +48,19 @@
function refresh() {
window.location.reload();
}
+
+ /** @param {import('$pluginTypes').PluginDefModel} item */
+ async function clickView(item) {
+ const text = `view plugin ${item.name}`;
+ /** @type {import('$conversationTypes').MessageData} */
+ const data = {
+ postback: {
+ payload: 'hi world'
+ },
+ states: []
+ };
+ sendToChatBot(CHAT_FRAME_ID, text, data);
+ }
@@ -75,17 +91,22 @@
{item.enabled ? $_("Enabled") : $_("Disabled")}
{#if item.agent_ids.length > 0}
- {item.agent_ids.length} Agent(s)
+ {item.agent_ids.length} Agent(s)
{/if}
{$_('Public')}
-
{$_('View')}
+
clickView(item)}
+ >
+ {$_('View')}
+
{#if item.settings_name}
-
{$_('Settings')}
+
{$_('Settings')}
{/if}
{#if !item.is_core}
-
handlePluginStatus(item.id, item.name, !item.enabled)}>{item.enabled ? $_("Remove") : $_("Install")}
+
handlePluginStatus(item.id, item.name, !item.enabled)}>{item.enabled ? $_("Remove") : $_("Install")}
{/if}
From 788e9fffd667d4c2775c9af1b07fc02490153e15 Mon Sep 17 00:00:00 2001
From: Jicheng Lu <103353@smsassist.com>
Date: Wed, 25 Sep 2024 16:46:08 -0500
Subject: [PATCH 2/2] resist chatbox
---
src/lib/common/LiveChatEntry.svelte | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/src/lib/common/LiveChatEntry.svelte b/src/lib/common/LiveChatEntry.svelte
index 5450cc55..6c55fad2 100644
--- a/src/lib/common/LiveChatEntry.svelte
+++ b/src/lib/common/LiveChatEntry.svelte
@@ -47,6 +47,14 @@
openChatBox()}>
+
{/if}