edit()}>
{#if !!value?.trim()}
{value}
{:else}
diff --git a/src/lib/helpers/constants.js b/src/lib/helpers/constants.js
index d85ffe1f..aa550b80 100644
--- a/src/lib/helpers/constants.js
+++ b/src/lib/helpers/constants.js
@@ -5,7 +5,13 @@ export const CHAT_FRAME_ID = "chatbox-frame";
export const USER_SENDERS = [
UserRole.Admin,
UserRole.User,
- UserRole.Client
+ UserRole.Client,
+ UserRole.Root
+];
+
+export const ADMIN_ROLES = [
+ UserRole.Admin,
+ UserRole.Root
];
export const BOT_SENDERS = [
diff --git a/src/lib/helpers/enums.js b/src/lib/helpers/enums.js
index b7a4feaf..4583819c 100644
--- a/src/lib/helpers/enums.js
+++ b/src/lib/helpers/enums.js
@@ -4,7 +4,8 @@ const userRole = {
User: "user",
Client: "client",
Function: "function",
- Assistant: "assistant"
+ Assistant: "assistant",
+ Root: "root"
};
export const UserRole = Object.freeze(userRole);
@@ -115,4 +116,15 @@ const conversationTag = {
Evaluation: "evaluation-set",
Test: "test-set"
};
-export const ConversationTag = Object.freeze(conversationTag);
\ No newline at end of file
+export const ConversationTag = Object.freeze(conversationTag);
+
+const userPermission = {
+ CreateAgent: "create-agent"
+};
+export const UserPermission = Object.freeze(userPermission);
+
+const userAction = {
+ Edit: "edit",
+ Chat: "chat"
+};
+export const UserAction = Object.freeze(userAction);
\ No newline at end of file
diff --git a/src/lib/helpers/http.js b/src/lib/helpers/http.js
index cfcd4bf7..7f53127e 100644
--- a/src/lib/helpers/http.js
+++ b/src/lib/helpers/http.js
@@ -61,12 +61,14 @@ function skipLoader(config) {
new RegExp('http(s*)://(.*?)/knowledge/(.*?)/search', 'g'),
new RegExp('http(s*)://(.*?)/knowledge/vector/(.*?)/create', 'g'),
new RegExp('http(s*)://(.*?)/knowledge/document/(.*?)/page', 'g'),
+ new RegExp('http(s*)://(.*?)/users', 'g')
];
const putRegexes = [
new RegExp('http(s*)://(.*?)/knowledge/vector/(.*?)/update', 'g'),
new RegExp('http(s*)://(.*?)/conversation/(.*?)/update-message', 'g'),
new RegExp('http(s*)://(.*?)/conversation/(.*?)/update-tags', 'g'),
+ new RegExp('http(s*)://(.*?)/users', 'g'),
];
const deleteRegexes = [
diff --git a/src/lib/helpers/types/agentTypes.js b/src/lib/helpers/types/agentTypes.js
index 0caa9854..d429c2db 100644
--- a/src/lib/helpers/types/agentTypes.js
+++ b/src/lib/helpers/types/agentTypes.js
@@ -58,6 +58,7 @@
* @property {RoutingRule[]} routing_rules
* @property {AgentWelcomeInfo} welcome_info - Welcome information.
* @property {boolean} editable
+ * @property {boolean} chatable
*/
diff --git a/src/lib/helpers/types/userTypes.js b/src/lib/helpers/types/userTypes.js
index 3f50a321..529afe2b 100644
--- a/src/lib/helpers/types/userTypes.js
+++ b/src/lib/helpers/types/userTypes.js
@@ -7,13 +7,45 @@
* @property {string} [full_name] - The user full name.
* @property {string} [email] - The user email.
* @property {string} source - Account source.
+ * @property {string?} [type] - Account source.
* @property {string} [external_id] - The user external id.
+ * @property {string[]} permissions - Permissions.
+ * @property {UserAgentAction[]} agent_actions - Agent actions
* @property {string} [create_date] - The user create date.
* @property {string} [update_date] - The user update date.
* @property {string} [role] - The user role.
* @property {string} [avatar] - The user avatar.
* @property {string} [color]
* @property {string} [token]
+ * @property {boolean} [open_detail]
+ */
+
+/**
+ * @typedef {Object} UserAgentAction
+ * @property {string?} [id] - The id
+ * @property {string} agent_id - The agent id
+ * @property {import('$agentTypes').AgentModel} [agent] - The agent details
+ * @property {string[]} actions - The actions
+ */
+
+/**
+ * @typedef {Object} UserAgentInnerAction
+ * @property {string?} [id] - The id
+ * @property {string} agent_id - The agent id
+ * @property {string} [agent_name] - The agent name
+ * @property {import('$agentTypes').AgentModel} [agent] - The agent details
+ * @property {{ key: string, value: string, checked: boolean }[]} actions - The actions
+ */
+
+/**
+ * @typedef {Object} UserFilter
+ * @property {number} page - The page number
+ * @property {number} size - The page size
+ * @property {string[]} [user_ids] - The user ids.
+ * @property {string[]} [user_names] - The user names
+ * @property {string[]} [roles] - The roles.
+ * @property {string[]} [sources] - The sources.
+ * @property {string[]} [external_ids] - The external ids.
*/
export default {};
\ No newline at end of file
diff --git a/src/lib/scss/app.scss b/src/lib/scss/app.scss
index 78f25531..389b85c0 100644
--- a/src/lib/scss/app.scss
+++ b/src/lib/scss/app.scss
@@ -92,6 +92,7 @@ File: Main Css File
@import "custom/pages/conversation";
@import "custom/pages/agent";
@import "custom/pages/knowledgebase";
+@import "custom/pages/users";
// Common
@import "custom/common/animation";
diff --git a/src/lib/scss/custom/common/_common.scss b/src/lib/scss/custom/common/_common.scss
index c5ff3913..1a58aac4 100644
--- a/src/lib/scss/custom/common/_common.scss
+++ b/src/lib/scss/custom/common/_common.scss
@@ -157,6 +157,11 @@ button:focus {
justify-content:center;
}
+.div-center {
+ display: flex;
+ justify-content:center;
+}
+
.ellipsis {
white-space: nowrap;
overflow: hidden;
@@ -171,6 +176,10 @@ button:focus {
.danger-background {
background-color: $danger !important;
}
+
+.thin-scrollbar {
+ scrollbar-width: thin;
+}
.markdown-container {
overflow-x: auto;
diff --git a/src/lib/scss/custom/components/_chat.scss b/src/lib/scss/custom/components/_chat.scss
index 14fa8eaa..291ea7cf 100644
--- a/src/lib/scss/custom/components/_chat.scss
+++ b/src/lib/scss/custom/components/_chat.scss
@@ -54,7 +54,7 @@ $bubble-chat-theme-color: rgba($primary, 80%);
width: 100%;
z-index: 999;
padding: 10px 15px;
- background-color: rgb(255, 255, 239);
+ background-color: white;
}
.chat-util-item {
diff --git a/src/lib/scss/custom/pages/_users.scss b/src/lib/scss/custom/pages/_users.scss
new file mode 100644
index 00000000..feddbf37
--- /dev/null
+++ b/src/lib/scss/custom/pages/_users.scss
@@ -0,0 +1,98 @@
+.users-table {
+ .user-plain-col {
+ width: 10%;
+ max-width: 100px;
+ }
+
+ .user-permission-col {
+ width: 20%;
+ max-width: 300px;
+ }
+
+ .user-agent-col {
+ width: 25%;
+ max-width: 350px;
+ }
+
+ .user-detail {
+ padding: 2px 5px;
+ border-radius: 3px;
+ border-color: var(--#{$prefix}light) !important;
+ background-color: var(--#{$prefix}light) !important;
+ position: relative;
+
+ ul {
+ li {
+ margin: 2px 0px;
+ }
+ }
+
+ .wrappable {
+ white-space: wrap !important;
+ }
+
+ .basic-info {
+ margin: 15px 0px 8px 0px;
+ display: flex;
+ flex-wrap: wrap;
+
+ li {
+ flex: 0 0 50%;
+
+ .inline-edit {
+ display: flex;
+ gap: 3px;
+ }
+ }
+ }
+
+ .user-agent-container {
+ margin: 20px 0px;
+ padding: 0px 2rem;
+
+ .action-row-wrapper {
+ overflow-y: auto;
+ scrollbar-width: thin;
+ height: fit-content;
+ max-height: 300px;
+ }
+
+ .action-row {
+ display: flex;
+ }
+
+ .action-col {
+ padding: 3px 0px;
+
+ input[type='checkbox'] {
+ outline: none !important;
+ box-shadow: none !important;
+ }
+ }
+
+ .action-title {
+ .action-title-wrapper {
+ display: flex;
+ gap: 3px;
+ justify-content: center;
+ text-transform: capitalize;
+ text-align: center;
+ border-bottom: 2px solid var(--bs-primary);
+ }
+ }
+
+ .action-center {
+ display: flex;
+ justify-content: center;
+ }
+ }
+
+ .edit-btn {
+ display: flex;
+ justify-content: flex-end;
+ font-size: 16px;
+ margin-top: 3px;
+ margin-right: 5px;
+ }
+ }
+}
diff --git a/src/lib/services/agent-service.js b/src/lib/services/agent-service.js
index 970ab721..73193cae 100644
--- a/src/lib/services/agent-service.js
+++ b/src/lib/services/agent-service.js
@@ -14,13 +14,15 @@ export async function getSettings() {
/**
* Get agent list
* @param {import('$agentTypes').AgentFilter} filter
+ * @param {boolean} checkAuth
* @returns {Promise
>}
*/
-export async function getAgents(filter) {
+export async function getAgents(filter, checkAuth = false) {
let url = endpoints.agentListUrl;
const response = await axios.get(url, {
params: {
- ...filter
+ ...filter,
+ checkAuth : checkAuth
},
paramsSerializer: {
dots: true,
diff --git a/src/lib/services/api-endpoints.js b/src/lib/services/api-endpoints.js
index 2d099617..1c4a95d4 100644
--- a/src/lib/services/api-endpoints.js
+++ b/src/lib/services/api-endpoints.js
@@ -5,6 +5,8 @@ export const endpoints = {
// user
tokenUrl: `${host}/token`,
myInfoUrl: `${host}/user/me`,
+ usersUrl: `${host}/users`,
+ userUpdateUrl: `${host}/user`,
usrCreationUrl: `${host}/user`,
userAvatarUrl: `${host}/user/avatar`,
diff --git a/src/lib/services/user-service.js b/src/lib/services/user-service.js
new file mode 100644
index 00000000..dacb88d5
--- /dev/null
+++ b/src/lib/services/user-service.js
@@ -0,0 +1,23 @@
+import { endpoints } from './api-endpoints.js';
+import axios from 'axios';
+
+/**
+ * Get user list
+ * @param {import('$userTypes').UserFilter} filter
+ * @returns {Promise>}
+ */
+export async function getUsers(filter) {
+ const response = await axios.post(endpoints.usersUrl, { ...filter });
+ return response.data;
+}
+
+
+/**
+ * Get user list
+ * @param {import('$userTypes').UserModel} model
+ * @returns {Promise}
+ */
+export async function updateUser(model) {
+ const response = await axios.put(endpoints.userUpdateUrl, { ...model });
+ return response.data;
+}
\ No newline at end of file
diff --git a/src/routes/chat/+page.svelte b/src/routes/chat/+page.svelte
index 63777ae7..30f02cc0 100644
--- a/src/routes/chat/+page.svelte
+++ b/src/routes/chat/+page.svelte
@@ -16,7 +16,7 @@
let agentId = 'undefined';
onMount(async () => {
- const response = await getAgents(filter);
+ const response = await getAgents(filter, true);
agents = response?.items?.map(t => { return { ...t }; }) || [];
const agentSettings = await getSettingDetail("Agent");
// @ts-ignore
diff --git a/src/routes/chat/[agentId]/[conversationId]/chat-box.svelte b/src/routes/chat/[agentId]/[conversationId]/chat-box.svelte
index fec3ff64..8ca3a5a7 100644
--- a/src/routes/chat/[agentId]/[conversationId]/chat-box.svelte
+++ b/src/routes/chat/[agentId]/[conversationId]/chat-box.svelte
@@ -43,7 +43,7 @@
PUBLIC_LIVECHAT_ENABLE_TRAINING,
PUBLIC_DEBUG_MODE
} from '$env/static/public';
- import { BOT_SENDERS, LERNER_ID, TEXT_EDITORS, TRAINING_MODE, USER_SENDERS } from '$lib/helpers/constants';
+ import { BOT_SENDERS, LERNER_ID, TEXT_EDITORS, TRAINING_MODE, USER_SENDERS, ADMIN_ROLES } from '$lib/helpers/constants';
import { signalr } from '$lib/services/signalr-service.js';
import { webSpeech } from '$lib/services/web-speech.js';
import { newConversation } from '$lib/services/conversation-service';
@@ -201,7 +201,7 @@
}
$: {
- disableAction = currentUser?.role !== UserRole.Admin && currentUser?.id !== conversationUser?.id;
+ disableAction = !ADMIN_ROLES.includes(currentUser?.role || '') && currentUser?.id !== conversationUser?.id || !agent?.chatable;
}
setContext('chat-window-context', {
@@ -1504,8 +1504,12 @@
{/if}
- {#if currentUser?.role === UserRole.Admin}
- toggleTagModal()}>
+
+ {#if ADMIN_ROLES.includes(currentUser?.role || '')}
+ toggleTagModal()}
+ >
Add Tags
{/if}
diff --git a/src/routes/page/agent/+page.svelte b/src/routes/page/agent/+page.svelte
index c3566729..516bbe66 100644
--- a/src/routes/page/agent/+page.svelte
+++ b/src/routes/page/agent/+page.svelte
@@ -11,6 +11,8 @@
import { _ } from 'svelte-i18n'
import { goto } from '$app/navigation';
import Swal from 'sweetalert2';
+ import { UserPermission } from '$lib/helpers/enums';
+ import { ADMIN_ROLES } from '$lib/helpers/constants';
const firstPage = 1;
@@ -43,7 +45,7 @@
function getPagedAgents() {
isLoading = true;
- getAgents(filter).then(data => {
+ getAgents(filter, true).then(data => {
agents = data;
}).catch(() => {
agents = { items: [], count: 0 };
@@ -124,7 +126,7 @@
-{#if !!user}
+{#if !!user && (ADMIN_ROLES.includes(user.role || '') || !!user.permissions?.includes(UserPermission.CreateAgent))}
@@ -134,4 +136,4 @@
-
\ No newline at end of file
+ pageTo(pn)} />
\ No newline at end of file
diff --git a/src/routes/page/agent/[agentId]/+page.svelte b/src/routes/page/agent/[agentId]/+page.svelte
index 1cab3186..84cc4bd0 100644
--- a/src/routes/page/agent/[agentId]/+page.svelte
+++ b/src/routes/page/agent/[agentId]/+page.svelte
@@ -119,6 +119,7 @@
title: 'Are you sure?',
text: "Are you sure you want to delete this agent?",
icon: 'warning',
+ customClass: { confirmButton: 'danger-background' },
showCancelButton: true,
cancelButtonText: 'No',
confirmButtonText: 'Yes'
diff --git a/src/routes/page/agent/[agentId]/agent-overview.svelte b/src/routes/page/agent/[agentId]/agent-overview.svelte
index eb9682d0..e4a5e5c9 100644
--- a/src/routes/page/agent/[agentId]/agent-overview.svelte
+++ b/src/routes/page/agent/[agentId]/agent-overview.svelte
@@ -75,15 +75,17 @@
height="50"
class="mx-auto d-block"
/>
-
+ {#if !!agent.chatable}
+
+ {/if}