From 2e653ed15e75fc6c965bd2aad7f4878facc554d5 Mon Sep 17 00:00:00 2001 From: ruwinirathnamalala Date: Thu, 18 Jun 2026 11:26:38 +0530 Subject: [PATCH 1/2] =?UTF-8?q?Consolidate=20Test=20LLM=20screens=20into?= =?UTF-8?q?=20a=20single=20screen=20with=20LLM=20connection=E2=80=A6=20(#4?= =?UTF-8?q?71)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Consolidate Test LLM screens into a single screen with LLM connection selector * Removed testmodel index and css --------- Co-authored-by: Charith Nuwan Bimsara <59943919+nuwangeek@users.noreply.github.com> --- .../POST/get-llm-connections-paginated.sql | 2 +- GUI/src/App.tsx | 3 +- GUI/src/components/MainNavigation/index.tsx | 6 - GUI/src/pages/TestModel/TestLLM.scss | 217 ----------------- GUI/src/pages/TestModel/index.tsx | 228 ------------------ .../TestProductionLLM/TestProductionLLM.scss | 15 ++ GUI/src/pages/TestProductionLLM/index.tsx | 65 ++++- 7 files changed, 80 insertions(+), 456 deletions(-) delete mode 100644 GUI/src/pages/TestModel/TestLLM.scss delete mode 100644 GUI/src/pages/TestModel/index.tsx diff --git a/DSL/Resql/rag-search/POST/get-llm-connections-paginated.sql b/DSL/Resql/rag-search/POST/get-llm-connections-paginated.sql index 922c16ec..d4c15efb 100644 --- a/DSL/Resql/rag-search/POST/get-llm-connections-paginated.sql +++ b/DSL/Resql/rag-search/POST/get-llm-connections-paginated.sql @@ -24,7 +24,7 @@ SELECT END AS budget_status FROM rag_search.llm_connections WHERE connection_status <> 'deleted' - AND environment = 'testing' + -- AND environment = 'testing' AND (:llm_platform IS NULL OR :llm_platform = '' OR llm_platform = :llm_platform) AND (:llm_model IS NULL OR :llm_model = '' OR llm_model = :llm_model) AND (:environment IS NULL OR :environment = '' OR environment = :environment) diff --git a/GUI/src/App.tsx b/GUI/src/App.tsx index 5839b180..43c50753 100644 --- a/GUI/src/App.tsx +++ b/GUI/src/App.tsx @@ -64,8 +64,7 @@ const App: FC = () => { } /> } /> } /> - } /> - } /> + } /> diff --git a/GUI/src/components/MainNavigation/index.tsx b/GUI/src/components/MainNavigation/index.tsx index 070c4b9a..8ae278ca 100644 --- a/GUI/src/components/MainNavigation/index.tsx +++ b/GUI/src/components/MainNavigation/index.tsx @@ -44,12 +44,6 @@ const MainNavigation: FC = () => { label: t('menu.testLLM'), path: '/test-llm', icon: - }, - { - id: 'testProductionLLM', - label: t('menu.testProductionLLM'), - path: '/test-production-llm', - icon: } ]; diff --git a/GUI/src/pages/TestModel/TestLLM.scss b/GUI/src/pages/TestModel/TestLLM.scss deleted file mode 100644 index 3d0c2156..00000000 --- a/GUI/src/pages/TestModel/TestLLM.scss +++ /dev/null @@ -1,217 +0,0 @@ -.testModalFormTextArea { - margin-top: 30px; -} - -.mcq-buttons { - display: flex; - flex-wrap: wrap; - gap: 0.75rem; - margin-top: 1rem; -} - -.testModalClassifyButton { - text-align: right; - margin-top: 20px; -} - -.llm-connection-section { - width: 50%; -} - -.llm-connection-controls { - display: flex; - gap: 1rem; - align-items: center; -} - -.inference-results-container { - max-width: 100%; - background-color: #d7efff; - padding: 20px; - border-radius: 8px; - margin-top: 20px; - - .result-item { - margin-bottom: 15px; - - strong { - color: #333; - } - } - - .response-content { - margin-top: 8px; - padding: 12px; - background-color: #f5f5f5; - border-radius: 4px; - white-space: pre-wrap; - line-height: 1.5; - color: #555; - } - - .context-section { - margin-top: 20px; - - .context-list { - display: flex; - flex-direction: column; - gap: 12px; - margin-top: 8px; - } - - .context-item { - padding: 12px; - background-color: #ffffff; - border: 1px solid #e0e0e0; - border-radius: 6px; - box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); - - .context-rank { - margin-bottom: 8px; - padding-bottom: 4px; - border-bottom: 1px solid #f0f0f0; - - strong { - color: #2563eb; - font-size: 0.875rem; - font-weight: 600; - } - } - - .context-content { - color: #374151; - line-height: 1.5; - font-size: 0.9rem; - white-space: pre-wrap; - } - } - } -} - -.testModalList { - list-style: disc; - margin-left: 30px; -} - -.mt-20 { - margin-top: 20px; -} - -.classification-results { - margin-top: 1rem; - padding: 1rem; - border: 1px solid #e0e0e0; - border-radius: 8px; - background-color: #f9f9f9; - - h3 { - margin: 0 0 1rem 0; - color: #333; - } - - h4 { - margin: 0 0 0.75rem 0; - color: #555; - font-size: 1rem; - } - - .results-container { - display: flex; - flex-direction: column; - gap: 1.5rem; - } - - .top-prediction { - .prediction-card { - display: flex; - justify-content: space-between; - align-items: center; - padding: 1rem; - border-radius: 8px; - background-color: #e8f5e8; - border: 2px solid #4caf50; - - .agency-name { - font-weight: 600; - color: #2e7d32; - font-size: 1.1rem; - } - - .confidence-score { - font-weight: 700; - color: #2e7d32; - font-size: 1.2rem; - } - } - } - - .predictions-list { - display: flex; - flex-direction: column; - gap: 0.75rem; - - .prediction-item { - display: flex; - align-items: center; - gap: 1rem; - padding: 0.75rem; - background-color: white; - border-radius: 6px; - border: 1px solid #ddd; - - &.highest { - border-color: #4caf50; - background-color: #f8fff8; - } - - .rank { - font-weight: 600; - color: #666; - min-width: 2rem; - } - - .agency-info { - flex: 1; - display: flex; - flex-direction: column; - gap: 0.25rem; - - .agency-name { - font-weight: 500; - color: #333; - } - - .confidence-bar-container { - width: 100%; - height: 4px; - background-color: #e0e0e0; - border-radius: 2px; - overflow: hidden; - - .confidence-bar { - height: 100%; - background-color: #4caf50; - transition: width 0.3s ease; - } - } - } - - .confidence-percentage { - font-weight: 600; - color: #555; - min-width: 4rem; - text-align: right; - } - } - } -} - -.classification-error { - margin-top: 1rem; - padding: 1rem; - background-color: #ffebee; - border: 1px solid #f44336; - border-radius: 6px; - color: #c62828; - text-align: center; -} \ No newline at end of file diff --git a/GUI/src/pages/TestModel/index.tsx b/GUI/src/pages/TestModel/index.tsx deleted file mode 100644 index 2fc116bd..00000000 --- a/GUI/src/pages/TestModel/index.tsx +++ /dev/null @@ -1,228 +0,0 @@ -import { useMutation, useQuery } from '@tanstack/react-query'; -import { Button, FormSelect, FormTextarea, Collapsible } from 'components'; -import CircularSpinner from 'components/molecules/CircularSpinner/CircularSpinner'; -import { ComponentPropsWithoutRef, FC, useState } from 'react'; -import { useTranslation } from 'react-i18next'; -import ReactMarkdown from 'react-markdown'; -import remarkGfm from 'remark-gfm'; -import './TestLLM.scss'; -import { useDialog } from 'hooks/useDialog'; -import { fetchLLMConnectionsPaginated, LegacyLLMConnectionFilters } from 'services/llmConnections'; -import { viewInferenceResult, InferenceRequest, InferenceResponse, ChoiceButton } from 'services/inference'; -import { llmConnectionsQueryKeys } from 'utils/queryKeys'; -import { ButtonAppearanceTypes } from 'enums/commonEnums'; - -const TestLLM: FC = () => { - const { t } = useTranslation(); - const { open: openDialog, close: closeDialog } = useDialog(); - const [inferenceResult, setInferenceResult] = useState(null); - const [pendingButtons, setPendingButtons] = useState([]); - const [testLLM, setTestLLM] = useState({ - connectionId: null, - text: '', - }); - - // Sort context by rank - const sortedContext = inferenceResult?.chunks?.toSorted((a, b) => a.rank - b.rank) ?? []; - - // Fetch LLM connections for dropdown - using the working legacy endpoint for now - const { data: connections, isLoading: isLoadingConnections } = useQuery({ - queryKey: llmConnectionsQueryKeys.list({ - page: 1, - pageSize: 100, // Get all connections for dropdown - sorting: 'created_at desc', - }), - queryFn: () => fetchLLMConnectionsPaginated({ - pageNumber: 1, - pageSize: 100, - sortBy: 'created_at desc', - }), - }); - - // Transform connections data for dropdown - const connectionOptions = connections?.map((connection: any) => ({ - label: `${connection.llmPlatform} - ${connection.llmModel} (${connection.environment})`, - value: connection.id, - })) || []; - - // Inference mutation - const inferenceMutation = useMutation({ - mutationFn: (request: InferenceRequest) => viewInferenceResult(request), - onSuccess: (data: InferenceResponse) => { - setInferenceResult(data?.response); - setPendingButtons(data?.response?.buttons ?? []); - }, - onError: (error: any) => { - console.error('Error getting inference result:', error); - openDialog({ - title: t('testModels.inferenceErrorTitle') || 'Inference Error', - content:

{t('testModels.inferenceErrorMessage') || 'Failed to get inference result. Please try again.'}

, - footer: ( - - ), - }); - }, - }); - - const handleSend = () => { - if (testLLM.connectionId && testLLM.text) { - inferenceMutation.mutate({ - llmConnectionId: Number(testLLM.connectionId), - message: testLLM.text, - }); - } - }; - - const handleButtonClick = (payload: string) => { - if (!testLLM.connectionId) return; - setPendingButtons([]); - inferenceMutation.mutate({ - llmConnectionId: Number(testLLM.connectionId), - message: payload, - }); - }; - - const handleChange = (key: string, value: string | number) => { - // Prevent changes while inference is loading - if (inferenceMutation.isLoading) { - return; - } - setTestLLM((prev) => ({ - ...prev, - [key]: value, - })); - }; - - const markdownComponents = { - ol: ({children}: any) => ( -
    - {children} -
- ), - a: (props: ComponentPropsWithoutRef<"a">) => ( - - ), - }; - - return ( -
- {isLoadingConnections ? ( - - ) : ( -
-
-
{t('testModels.title') || 'Test LLM'}
-
-
-

{t('testModels.llmConnectionLabel') || 'LLM Connection'}

-
- - { - handleChange('connectionId', selection?.value as string); - }} - value={testLLM?.connectionId === null ? t('testModels.connectionNotExist') || 'Connection does not exist' : undefined} - defaultValue={testLLM?.connectionId ?? undefined} - disabled={inferenceMutation.isLoading} - /> -
-
- -
-

{t('testModels.classifyTextLabel') || 'Enter text to test'}

- handleChange('text', e.target.value)} - showMaxLength={true} - /> -
-
- -
- - {/* Inference Result */} - - {inferenceResult && !inferenceMutation.isLoading && ( -
-
- Response: -
- - {inferenceResult.content} - -
-
- - {/* MCQ Buttons */} - {pendingButtons.length > 0 && ( -
- {pendingButtons.map((btn) => ( - - ))} -
- )} - - {/* Context Section */} - { - sortedContext && sortedContext?.length > 0 && ( -
- -
- {sortedContext?.map((contextItem, index) => ( -
-
- Rank {contextItem.rank} -
-
- - {contextItem.chunkRetrieved} - -
-
- ))} -
-
-
- ) - } - -
- )} - - {/* Error State */} - {inferenceMutation.isError && ( -
-

{t('testModels.classificationFailed') || 'Inference failed. Please try again.'}

-
- )} -
- )} -
- ); -}; - -export default TestLLM; \ No newline at end of file diff --git a/GUI/src/pages/TestProductionLLM/TestProductionLLM.scss b/GUI/src/pages/TestProductionLLM/TestProductionLLM.scss index 9cb5c00c..2fa456fb 100644 --- a/GUI/src/pages/TestProductionLLM/TestProductionLLM.scss +++ b/GUI/src/pages/TestProductionLLM/TestProductionLLM.scss @@ -3,6 +3,21 @@ margin: 0 auto; padding: 2rem; + .llm-connection-section { + width: 50%; + margin-bottom: 1.5rem; + p { + margin-bottom: 0.5rem; + font-weight: 500; + color: #333; + } + } + .llm-connection-controls { + display: flex; + gap: 1rem; + align-items: center; + } + .mcq-buttons { display: flex; flex-wrap: wrap; diff --git a/GUI/src/pages/TestProductionLLM/index.tsx b/GUI/src/pages/TestProductionLLM/index.tsx index f29cfcf9..b9ba6be7 100644 --- a/GUI/src/pages/TestProductionLLM/index.tsx +++ b/GUI/src/pages/TestProductionLLM/index.tsx @@ -1,11 +1,16 @@ import { FC, useState, useRef, useEffect, useMemo } from 'react'; +import { useQuery } from '@tanstack/react-query'; import { useTranslation } from 'react-i18next'; -import { Button, FormTextarea } from 'components'; +import { Button, FormTextarea, FormSelect } from 'components'; import { useToast } from 'hooks/useToast'; import { useStreamingResponse } from 'hooks/useStreamingResponse'; import { ChoiceButton } from 'services/inference'; import './TestProductionLLM.scss'; import MessageContent from 'components/MessageContent'; +import { llmConnectionsQueryKeys } from 'utils/queryKeys'; +import { fetchLLMConnectionsPaginated } from 'services/llmConnections'; + + interface Message { id: string; content: string; @@ -23,11 +28,49 @@ const TestProductionLLM: FC = () => { const [messages, setMessages] = useState([]); const [isLoading, setIsLoading] = useState(false); const messagesEndRef = useRef(null); + const [testLLM, setTestLLM] = useState({ + connectionId: null, + text: '', + }); // Generate a unique channel ID for this session const channelId = useMemo(() => `channel-${Math.random().toString(36).substring(2, 15)}`, []); const { startStreaming, stopStreaming, isStreaming } = useStreamingResponse(channelId); + const [selectedConnectionId, setSelectedConnectionId] = useState(null); + + // Fetch LLM connections for dropdown - using the working legacy endpoint for now + const { data: connections, isLoading: isLoadingConnections } = useQuery({ + queryKey: llmConnectionsQueryKeys.list({ + page: 1, + pageSize: 100, // Get all connections for dropdown + sorting: 'created_at desc', + }), + queryFn: () => fetchLLMConnectionsPaginated({ + pageNumber: 1, + pageSize: 100, + sortBy: 'created_at desc', + }), + }); + // Transform connections data for dropdown + const connectionOptions = useMemo( + () => + connections?.map((connection: any) => ({ + label: `${connection.llmPlatform} - ${connection.llmModel} (${connection.environment})`, + value: String(connection.id), + })) || [], + [connections] + ); + const selectedConnection = useMemo(() => { + return connections?.find((conn: any) => String(conn.id) === selectedConnectionId) || null; + }, [connections, selectedConnectionId]); + + const handleConnectionChange = (value: string | number) => { + console.log('Selected connection ID:', value); + if (isLoading || isStreaming) return; + setSelectedConnectionId(value ? String(value) : null); + }; + // Auto-scroll to bottom useEffect(() => { messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' }); @@ -82,6 +125,8 @@ const TestProductionLLM: FC = () => { authorId: 'test-user-456', conversationHistory, url: 'opensearch-dashboard-test', + environment: selectedConnection?.environment || 'production', + connection_id: selectedConnection?.vaultUuid || undefined, }; // Callbacks for streaming @@ -257,11 +302,27 @@ const TestProductionLLM: FC = () => {
-

{t('testProductionLLM.title')}

+

{t('testModels.title')}

+
+

{t('testModels.llmConnectionLabel') || 'LLM Connection'}

+
+ { + handleConnectionChange(selection?.value as string); + }} + defaultValue={selectedConnectionId ?? undefined} + disabled={isLoading || isStreaming} + /> +
+
From 59c5765eea59d7f819cd3c96a795829f03fb043b Mon Sep 17 00:00:00 2001 From: ruwinirathnamalala Date: Thu, 18 Jun 2026 11:27:43 +0530 Subject: [PATCH 2/2] Sync menu headers (#474) * Consolidate Test LLM screens into a single screen with LLM connection selector * synced menu headers * Removed testmodel index and css * synced menu headers --------- Co-authored-by: Charith Nuwan Bimsara <59943919+nuwangeek@users.noreply.github.com> --- DSL/Ruuter.private/accounts/GET/user-role.yml | 38 +++++++++ .../rag-search/GET/accounts/user-role.yml | 38 +++++++++ GUI/.env.development | 4 +- GUI/package-lock.json | 80 ++++++++++++++++++- GUI/package.json | 4 +- GUI/src/components/Layout/index.tsx | 16 +++- GUI/src/store/index.ts | 4 + GUI/translations/en/common.json | 17 ++++ GUI/translations/et/common.json | 17 ++++ docker-compose-ec2.yml | 3 +- docker-compose.yml | 4 +- 11 files changed, 216 insertions(+), 9 deletions(-) create mode 100644 DSL/Ruuter.private/accounts/GET/user-role.yml create mode 100644 DSL/Ruuter.public/rag-search/GET/accounts/user-role.yml diff --git a/DSL/Ruuter.private/accounts/GET/user-role.yml b/DSL/Ruuter.private/accounts/GET/user-role.yml new file mode 100644 index 00000000..cd8f3830 --- /dev/null +++ b/DSL/Ruuter.private/accounts/GET/user-role.yml @@ -0,0 +1,38 @@ +declaration: + call: declare + version: 0.1 + description: "Get user roles dynamically from TIM" + method: get + accepts: json + returns: json + namespace: rag-search + allowlist: + headers: + - field: cookie + type: string + description: "Cookie field" + +get_user_info: + call: http.post + args: + url: "[#RAG_SEARCH_TIM]/jwt/custom-jwt-userinfo" + contentType: plaintext + headers: + cookie: ${incoming.headers.cookie} + plaintext: "customJwtCookie" + result: res + next: check_user_info_response + +check_user_info_response: + switch: + - condition: ${200 <= res.response.statusCodeValue && res.response.statusCodeValue < 300} + next: return_result + next: return_empty_array + +return_result: + return: ${res.response.body.authorities} + next: end + +return_empty_array: + return: success + next: end diff --git a/DSL/Ruuter.public/rag-search/GET/accounts/user-role.yml b/DSL/Ruuter.public/rag-search/GET/accounts/user-role.yml new file mode 100644 index 00000000..d37b8911 --- /dev/null +++ b/DSL/Ruuter.public/rag-search/GET/accounts/user-role.yml @@ -0,0 +1,38 @@ +declaration: + call: declare + version: 0.1 + description: "Get user roles dynamically from TIM" + method: get + accepts: json + returns: json + namespace: backoffice + allowlist: + headers: + - field: cookie + type: string + description: "Cookie field" + +get_user_info: + call: http.post + args: + url: "[#CKB_TIM]/jwt/custom-jwt-userinfo" + contentType: plaintext + headers: + cookie: ${incoming.headers.cookie} + plaintext: "customJwtCookie" + result: res + next: check_user_info_response + +check_user_info_response: + switch: + - condition: ${200 <= res.response.statusCodeValue && res.response.statusCodeValue < 300} + next: return_result + next: return_empty_array + +return_result: + return: ${res.response.body.authorities} + next: end + +return_empty_array: + return: success + next: end diff --git a/GUI/.env.development b/GUI/.env.development index ae5b1356..c15f05c6 100644 --- a/GUI/.env.development +++ b/GUI/.env.development @@ -4,4 +4,6 @@ REACT_APP_CUSTOMER_SERVICE_LOGIN=http://localhost:3004/et/dev-auth REACT_APP_SERVICE_ID=conversations,settings,monitoring REACT_APP_NOTIFICATION_NODE_URL=http://localhost:4040 REACT_APP_CSP=upgrade-insecure-requests; default-src 'self'; font-src 'self' data:; img-src 'self' data:; script-src 'self' 'unsafe-eval' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; object-src 'none'; connect-src 'self' http://localhost:8086 http://localhost:8088 http://localhost:3004 http://localhost:4040 ws://localhost; -REACT_APP_ENABLE_HIDDEN_FEATURES=TRUE \ No newline at end of file +REACT_APP_ENABLE_HIDDEN_FEATURES=TRUE +REACT_APP_ENABLE_MULTI_DOMAIN=FALSE +REACT_APP_MENU_JSON= '[{"id":"conversations","label":{"et":"Vestlused","en":"Conversations"},"path":"/chat","children":[{"label":{"et":"Vastamata","en":"Unanswered"},"path":"/unanswered"},{"label":{"et":"Aktiivsed","en":"Active"},"path":"/active"},{"label":{"et":"Ootel","en":"Pending"},"path":"/pending"},{"label":{"et":"Ajalugu","en":"History"},"path":"/history"},{"label":{"et":"Valideerimised","en":"Validations"},"path":"/validations"}]},{"id":"training","label":{"et":"Treening","en":"Training"},"path":"/training","children":[{"label":{"et":"Treening","en":"Training"},"path":"/training","children":[{"label":{"et":"Teemad","en":"Themes"},"path":"/training/intents"},{"hidden":true,"label":{"et":"Avalikud teemad","en":"Public themes"},"path":"/training/common-intents"},{"label":{"et":"Teemade järeltreenimine","en":"Post training themes"},"path":"/training/intents-followup-training"},{"label":{"et":"Vastused","en":"Answers"},"path":"/training/responses"},{"label":{"et":"Reeglid","en":"Rules"},"path":"/training/rules"},{"hidden":true,"label":{"et":"Konfiguratsioon","en":"Configuration"},"path":"/training/configuration"},{"label":{"et":"Vormid","en":"Forms"},"path":"/training/forms"},{"label":{"et":"Mälukohad","en":"Slots"},"path":"/training/slots"}]},{"label":{"et":"Ajaloolised vestlused","en":"Historical conversations"},"path":"/history","children":[{"label":{"et":"Ajalugu","en":"History"},"path":"/history/history"},{"hidden":true,"label":{"et":"Pöördumised","en":"Appeals"},"path":"/history/appeal"}]},{"label":{"et":"Mudelipank ja analüütika","en":"Modelbank and analytics"},"path":"/analytics","children":[{"label":{"et":"Teemade ülevaade","en":"Overview of topics"},"path":"/analytics/overview"},{"label":{"et":"Mudelite võrdlus","en":"Comparison of models"},"path":"/analytics/models"},{"hidden":true,"label":{"et":"Testlood","en":"testTracks"},"path":"/analytics/testcases"}]},{"label":{"et":"Treeni uus mudel","en":"Train new model"},"path":"/train-new-model"}]},{"id":"analytics","label":{"et":"Analüütika","en":"Analytics"},"path":"/analytics","children":[{"label":{"et":"Ülevaade","en":"Overview"},"path":"/overview"},{"label":{"et":"Vestlused","en":"Chats"},"path":"/chats"},{"label":{"et":"Tagasiside","en":"Feedback"},"path":"/feedback"},{"label":{"et":"Avaandmed","en":"Reports"},"path":"/reports"}]},{"id":"services","hidden":true,"label":{"et":"Teenused","en":"Services"},"path":"/services","children":[{"label":{"et":"Ülevaade","en":"Overview"},"path":"/overview"},{"label":{"et":"Uus teenus","en":"New Service"},"path":"/newService"},{"label":{"et":"Probleemsed teenused","en":"Faulty Services"},"path":"/faultyServices"}]},{"id":"knowledge-center","label":{"et":"Teadmuskeskus","en":"Knowledge Center"},"path":"/knowledge-center","children":[{"id":"rag-search","label":{"et":"Mudelid ja seadistused","en":"Models management"},"path":"/rag-search","children":[{"label":{"et":"Mudelite ühendused","en":"LLM connections"},"path":"/llm-connections"},{"label":{"et":"Viiba Seaded","en":"Prompt Configurations"},"path":"/prompt-configurations"},{"label":{"et":"Testi mudelit","en":"Test LLM"},"path":"/test-llm"}]},{"id":"ckb","label":{"et":"Teadmusbaas","en":"Knowledge Base"},"path":"/ckb","children":[{"label":{"et":"Agentuur","en":"Agency"},"path":"/agency"},{"label":{"et":"Aruanded","en":"Reports"},"path":"/reports"},{"label":{"et":"API Integratsioonid","en":"API Integrations"},"path":"/api"}]}]},{"id":"settings","label":{"et":"Haldus","en":"Administration"},"path":"/settings","children":[{"label":{"et":"Kasutajad","en":"Users"},"path":"/users"},{"label":{"et":"Vestlusbot","en":"Chatbot"},"path":"/chatbot","children":[{"label":{"et":"Seaded","en":"Settings"},"path":"/chatbot/settings"},{"label":{"et":"Tervitussõnum","en":"Welcome message"},"path":"/chatbot/welcome-message"},{"label":{"et":"Välimus ja käitumine","en":"Appearance and behavior"},"path":"/chatbot/appearance"},{"label":{"et":"Erakorralised teated","en":"Emergency notices"},"path":"/chatbot/emergency-notices"},{"label":{"et":"Tagasiside","en":"Feedback"},"path":"/chatbot/feedback"}]},{"label":{"et":"Vestluste analüüs","en":"Chat analysis"},"path":"/chat-analysis"},{"label":{"et":"Asutuse tööaeg","en":"Office opening hours"},"path":"/working-time"},{"label":{"et":"Vestluse Kustutamine","en":"Delete Conversations"},"path":"/delete-conversations"},{"label":{"et":"Sessiooni pikkus","en":"Session length"},"path":"/session-length"},{"label":{"et":"SKMi konfiguratsioon","en":"SKM Configuration"},"path":"/skm-configuration"},{"label":{"et":"Anonümiseerija","en":"Anonymizer"},"path":"/anonymizer"}]},{"id":"monitoring","hidden":true,"label":{"et":"Seire","en":"Monitoring"},"path":"/monitoring","children":[{"label":{"et":"Aktiivaeg","en":"Working hours"},"path":"/uptime"}]}]' diff --git a/GUI/package-lock.json b/GUI/package-lock.json index c0f45b17..5f1f779d 100644 --- a/GUI/package-lock.json +++ b/GUI/package-lock.json @@ -8,6 +8,8 @@ "name": "byk-training-module-gui", "version": "0.0.0", "dependencies": { + "@buerokratt-ria/header": "^0.1.52", + "@buerokratt-ria/menu": "^0.2.15", "@buerokratt-ria/styles": "^0.0.1", "@fontsource/roboto": "^4.5.8", "@formkit/auto-animate": "^1.0.0-beta.5", @@ -89,7 +91,7 @@ "eslint-plugin-typescript": "^0.14.0", "mocksse": "^1.0.4", "msw": "^0.49.2", - "prettier": "^2.8.1", + "prettier": "^2.8.8", "sass": "^1.57.0", "typescript": "^4.9.3", "vite": "^4.0.0", @@ -2154,6 +2156,81 @@ "node": ">=6.9.0" } }, + "node_modules/@buerokratt-ria/header": { + "version": "0.1.52", + "resolved": "https://registry.npmjs.org/@buerokratt-ria/header/-/header-0.1.52.tgz", + "integrity": "sha512-4k9Ekym6UqQpyF2nEIIT0n3wdp6Ax9sTvWK4HeZ7xuwf9YdgYnYRARRnZxcfsJCMm54JUQ8IKV9Y5i5ULVk1Bg==", + "license": "ISC", + "dependencies": { + "@buerokratt-ria/styles": "^0.0.1", + "@types/react": "^18.2.21", + "react": "^18.2.0" + }, + "peerDependencies": { + "@fontsource/roboto": "^4.5.8", + "@formkit/auto-animate": "^0.7.0", + "@radix-ui/react-accessible-icon": "^1.0.3", + "@radix-ui/react-dialog": "^1.0.4", + "@radix-ui/react-switch": "^1.0.3", + "@radix-ui/react-toast": "^1.1.4", + "@tanstack/react-query": "^4.32.1", + "axios": "^1.4.0", + "clsx": "^1.2.1", + "howler": "^2.2.4", + "i18next": "^23.2.3", + "i18next-browser-languagedetector": "^7.1.0", + "path": "^0.12.7", + "react": "^18.2.0", + "react-cookie": "^4.1.1", + "react-dom": "^18.2.0", + "react-hook-form": "^7.45.4", + "react-i18next": "^12.1.1", + "react-icons": "^4.10.1", + "react-idle-timer": "^5.7.2", + "react-router-dom": "^6.14.2", + "react-select": "^5.7.4", + "rxjs": "^7.8.1", + "tslib": "^2.3.0", + "vite-plugin-dts": "^3.5.2", + "vite-plugin-svgr": "^3.2.0", + "zustand": "^4.4.0" + } + }, + "node_modules/@buerokratt-ria/menu": { + "version": "0.2.15", + "resolved": "https://registry.npmjs.org/@buerokratt-ria/menu/-/menu-0.2.15.tgz", + "integrity": "sha512-xtjIyD/3Mdg2UZ7A6Yv/3ZsZX8LGUFGpYtr3LaYeyfhv5FsLWfDwXNPL2ViooOdpPJaD4hmKURrBF2VgpmBfUw==", + "license": "ISC", + "dependencies": { + "@buerokratt-ria/styles": "^0.0.1", + "@types/react": "^18.2.21", + "react": "^18.2.0" + }, + "peerDependencies": { + "@radix-ui/react-accessible-icon": "^1.0.3", + "@radix-ui/react-dialog": "^1.0.4", + "@radix-ui/react-switch": "^1.0.3", + "@radix-ui/react-toast": "^1.1.4", + "@tanstack/react-query": "^4.32.1", + "clsx": "^1.2.1", + "i18next": "^23.2.3", + "i18next-browser-languagedetector": "^7.1.0", + "path": "^0.12.7", + "react": "^18.2.0", + "react-cookie": "^4.1.1", + "react-dom": "^18.2.0", + "react-hook-form": "^7.45.4", + "react-i18next": "^12.1.1", + "react-icons": "^4.10.1", + "react-idle-timer": "^5.7.2", + "react-router-dom": "^6.14.2", + "rxjs": "^7.8.1", + "tslib": "^2.3.0", + "vite-plugin-dts": "^3.5.2", + "vite-plugin-svgr": "^3.2.0", + "zustand": "^4.4.0" + } + }, "node_modules/@buerokratt-ria/styles": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/@buerokratt-ria/styles/-/styles-0.0.1.tgz", @@ -14263,6 +14340,7 @@ "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", "dev": true, + "license": "MIT", "bin": { "prettier": "bin-prettier.js" }, diff --git a/GUI/package.json b/GUI/package.json index ec9c4e78..e1dc0692 100644 --- a/GUI/package.json +++ b/GUI/package.json @@ -11,6 +11,8 @@ "prettier": "prettier --write \"{,!(node_modules)/**/}*.{ts,tsx,js,json,css,less,scss}\"" }, "dependencies": { + "@buerokratt-ria/header": "^0.1.52", + "@buerokratt-ria/menu": "^0.2.15", "@buerokratt-ria/styles": "^0.0.1", "@fontsource/roboto": "^4.5.8", "@formkit/auto-animate": "^1.0.0-beta.5", @@ -92,7 +94,7 @@ "eslint-plugin-typescript": "^0.14.0", "mocksse": "^1.0.4", "msw": "^0.49.2", - "prettier": "^2.8.1", + "prettier": "^2.8.8", "sass": "^1.57.0", "typescript": "^4.9.3", "vite": "^4.0.0", diff --git a/GUI/src/components/Layout/index.tsx b/GUI/src/components/Layout/index.tsx index c26eca42..ef2864ad 100644 --- a/GUI/src/components/Layout/index.tsx +++ b/GUI/src/components/Layout/index.tsx @@ -3,15 +3,23 @@ import { Outlet } from 'react-router-dom'; import useStore from 'store'; import './Layout.scss'; import { useToast } from '../../hooks/useToast'; -import Header from 'components/Header'; -import MainNavigation from 'components/MainNavigation'; +import { MainNavigation } from '@buerokratt-ria/menu'; +import { Header, useMenuCountConf } from '@buerokratt-ria/header'; const Layout: FC = () => { + const domainBarShowing = import.meta.env.REACT_APP_ENABLE_MULTI_DOMAIN?.toLowerCase() === 'true'; + const menuCountConf = useMenuCountConf(); + return (
- +
-
+
diff --git a/GUI/src/store/index.ts b/GUI/src/store/index.ts index c5fe37db..16db7e6e 100644 --- a/GUI/src/store/index.ts +++ b/GUI/src/store/index.ts @@ -5,7 +5,9 @@ import { LLMConnectionFilters, ProductionConnectionFilters } from 'services/llmC interface StoreState { userInfo: UserInfo | null; userId: string; + userDomains: string[]; setUserInfo: (info: UserInfo) => void; + setUserDomains: (domains: string[]) => void; llmConnectionFilters: LLMConnectionFilters; llmConnectionPageIndex: number; productionConnectionFilters: ProductionConnectionFilters; @@ -32,7 +34,9 @@ const defaultProductionConnectionFilters: ProductionConnectionFilters = { const useStore = create((set) => ({ userInfo: null, userId: '', + userDomains: [], setUserInfo: (data) => set({ userInfo: data, userId: data?.userIdCode || '' }), + setUserDomains: (domains: string[]) => set({ userDomains: domains }), llmConnectionFilters: defaultLLMConnectionFilters, llmConnectionPageIndex: 1, productionConnectionFilters: defaultProductionConnectionFilters, diff --git a/GUI/translations/en/common.json b/GUI/translations/en/common.json index f3d932c7..21ef0c42 100644 --- a/GUI/translations/en/common.json +++ b/GUI/translations/en/common.json @@ -36,6 +36,11 @@ "endDate": "End date", "preview": "Preview", "logout": "Logout", + "present": "Present", + "away": "Away", + "csaStatus": "Customer support status", + "statusClarification": "Status clarification", + "notificationErrorMsg": "An error occurred", "change": "Change", "loading": "Loading", "asc": "asc", @@ -59,6 +64,18 @@ "entries": "records", "deleteSelected": "Delete selection" }, + "chat": { + "unanswered": "Unanswered", + "forwarded": "Forwarded", + "pending": "Pending" + }, + "mainMenu": { + "menuLabel": "Main navigation", + "closeMenu": "Collapse menu", + "openMenu": "Open menu", + "openIcon": "Open menu icon", + "closeIcon": "Close menu icon" + }, "menu": { "userManagement": "User management", "testLLM": "Test LLM", diff --git a/GUI/translations/et/common.json b/GUI/translations/et/common.json index 52e76621..b08826b4 100644 --- a/GUI/translations/et/common.json +++ b/GUI/translations/et/common.json @@ -36,6 +36,11 @@ "endDate": "Lõppkuupäev", "preview": "Eelvaade", "logout": "Logi välja", + "present": "Kohal", + "away": "Eemal", + "csaStatus": "Nõustaja", + "statusClarification": "Staatuse täpsustus", + "notificationErrorMsg": "Midagi läks valesti", "change": "Muuda", "loading": "Laadimine", "asc": "kasvav", @@ -59,6 +64,18 @@ "entries": "kirjeid", "deleteSelected": "Kustuta valik" }, + "chat": { + "unanswered": "Vastamata", + "forwarded": "Suunatud", + "pending": "Ootel" + }, + "mainMenu": { + "menuLabel": "Põhinavigatsioon", + "closeMenu": "Kitsenda menüü", + "openMenu": "Ava menüü", + "openIcon": "Ava menüü ikoon", + "closeIcon": "Sulge menüü ikoon" + }, "menu": { "userManagement": "Kasutajate haldus", "testLLM": "Testi mudelit", diff --git a/docker-compose-ec2.yml b/docker-compose-ec2.yml index a9052865..f1ab5f54 100644 --- a/docker-compose-ec2.yml +++ b/docker-compose-ec2.yml @@ -133,8 +133,9 @@ services: - DEBUG_ENABLED=true - CHOKIDAR_USEPOLLING=true - PORT=3001 - - REACT_APP_SERVICE_ID=conversations,settings,monitoring + - REACT_APP_SERVICE_ID=settings,services,training,rag-search,knowledge-center - REACT_APP_ENABLE_HIDDEN_FEATURES=TRUE + - REACT_APP_MENU_JSON= [{"id":"conversations","label":{"et":"Vestlused","en":"Conversations"},"path":"/chat","children":[{"label":{"et":"Vastamata","en":"Unanswered"},"path":"/unanswered"},{"label":{"et":"Aktiivsed","en":"Active"},"path":"/active"},{"label":{"et":"Ootel","en":"Pending"},"path":"/pending"},{"label":{"et":"Ajalugu","en":"History"},"path":"/history"},{"label":{"et":"Valideerimised","en":"Validations"},"path":"/validations"}]},{"id":"training","label":{"et":"Treening","en":"Training"},"path":"/training","children":[{"label":{"et":"Treening","en":"Training"},"path":"/training","children":[{"label":{"et":"Teemad","en":"Themes"},"path":"/training/intents"},{"hidden":true,"label":{"et":"Avalikud teemad","en":"Public themes"},"path":"/training/common-intents"},{"label":{"et":"Teemade järeltreenimine","en":"Post training themes"},"path":"/training/intents-followup-training"},{"label":{"et":"Vastused","en":"Answers"},"path":"/training/responses"},{"label":{"et":"Reeglid","en":"Rules"},"path":"/training/rules"},{"hidden":true,"label":{"et":"Konfiguratsioon","en":"Configuration"},"path":"/training/configuration"},{"label":{"et":"Vormid","en":"Forms"},"path":"/training/forms"},{"label":{"et":"Mälukohad","en":"Slots"},"path":"/training/slots"}]},{"label":{"et":"Ajaloolised vestlused","en":"Historical conversations"},"path":"/history","children":[{"label":{"et":"Ajalugu","en":"History"},"path":"/history/history"},{"hidden":true,"label":{"et":"Pöördumised","en":"Appeals"},"path":"/history/appeal"}]},{"label":{"et":"Mudelipank ja analüütika","en":"Modelbank and analytics"},"path":"/analytics","children":[{"label":{"et":"Teemade ülevaade","en":"Overview of topics"},"path":"/analytics/overview"},{"label":{"et":"Mudelite võrdlus","en":"Comparison of models"},"path":"/analytics/models"},{"hidden":true,"label":{"et":"Testlood","en":"testTracks"},"path":"/analytics/testcases"}]},{"label":{"et":"Treeni uus mudel","en":"Train new model"},"path":"/train-new-model"}]},{"id":"analytics","label":{"et":"Analüütika","en":"Analytics"},"path":"/analytics","children":[{"label":{"et":"Ülevaade","en":"Overview"},"path":"/overview"},{"label":{"et":"Vestlused","en":"Chats"},"path":"/chats"},{"label":{"et":"Tagasiside","en":"Feedback"},"path":"/feedback"},{"label":{"et":"Avaandmed","en":"Reports"},"path":"/reports"}]},{"id":"services","hidden":true,"label":{"et":"Teenused","en":"Services"},"path":"/services","children":[{"label":{"et":"Ülevaade","en":"Overview"},"path":"/overview"},{"label":{"et":"Uus teenus","en":"New Service"},"path":"/newService"},{"label":{"et":"Probleemsed teenused","en":"Faulty Services"},"path":"/faultyServices"}]},{"id":"knowledge-center","label":{"et":"Teadmuskeskus","en":"Knowledge Center"},"path":"/knowledge-center","children":[{"id":"rag-search","label":{"et":"Mudelid ja seadistused","en":"Models management"},"path":"/rag-search","children":[{"label":{"et":"Mudelite ühendused","en":"LLM connections"},"path":"/llm-connections"},{"label":{"et":"Viiba Seaded","en":"Prompt Configurations"},"path":"/prompt-configurations"},{"label":{"et":"Testi mudelit","en":"Test LLM"},"path":"/test-llm"}]},{"id":"ckb","label":{"et":"Teadmusbaas","en":"Knowledge Base"},"path":"/ckb","children":[{"label":{"et":"Agentuur","en":"Agency"},"path":"/agency"},{"label":{"et":"Aruanded","en":"Reports"},"path":"/reports"},{"label":{"et":"API Integratsioonid","en":"API Integrations"},"path":"/api"}]}]},{"id":"settings","label":{"et":"Haldus","en":"Administration"},"path":"/settings","children":[{"label":{"et":"Kasutajad","en":"Users"},"path":"/users"},{"label":{"et":"Vestlusbot","en":"Chatbot"},"path":"/chatbot","children":[{"label":{"et":"Seaded","en":"Settings"},"path":"/chatbot/settings"},{"label":{"et":"Tervitussõnum","en":"Welcome message"},"path":"/chatbot/welcome-message"},{"label":{"et":"Välimus ja käitumine","en":"Appearance and behavior"},"path":"/chatbot/appearance"},{"label":{"et":"Erakorralised teated","en":"Emergency notices"},"path":"/chatbot/emergency-notices"},{"label":{"et":"Tagasiside","en":"Feedback"},"path":"/chatbot/feedback"}]},{"label":{"et":"Vestluste analüüs","en":"Chat analysis"},"path":"/chat-analysis"},{"label":{"et":"Asutuse tööaeg","en":"Office opening hours"},"path":"/working-time"},{"label":{"et":"Vestluse Kustutamine","en":"Delete Conversations"},"path":"/delete-conversations"},{"label":{"et":"Sessiooni pikkus","en":"Session length"},"path":"/session-length"},{"label":{"et":"SKMi konfiguratsioon","en":"SKM Configuration"},"path":"/skm-configuration"},{"label":{"et":"Anonümiseerija","en":"Anonymizer"},"path":"/anonymizer"}]},{"id":"monitoring","hidden":true,"label":{"et":"Seire","en":"Monitoring"},"path":"/monitoring","children":[{"label":{"et":"Aktiivaeg","en":"Working hours"},"path":"/uptime"}]}] - VITE_HOST=0.0.0.0 - VITE_PORT=3001 - HOST=0.0.0.0 diff --git a/docker-compose.yml b/docker-compose.yml index ec324649..5e9c2962 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -132,8 +132,10 @@ services: - DEBUG_ENABLED=true - CHOKIDAR_USEPOLLING=true - PORT=3001 - - REACT_APP_SERVICE_ID=conversations,settings,monitoring + - REACT_APP_SERVICE_ID=settings,services,training,rag-search,knowledge-center - REACT_APP_ENABLE_HIDDEN_FEATURES=TRUE + - REACT_APP_ENABLE_MULTI_DOMAIN=FALSE + - REACT_APP_MENU_JSON= [{"id":"conversations","label":{"et":"Vestlused","en":"Conversations"},"path":"/chat","children":[{"label":{"et":"Vastamata","en":"Unanswered"},"path":"/unanswered"},{"label":{"et":"Aktiivsed","en":"Active"},"path":"/active"},{"label":{"et":"Ootel","en":"Pending"},"path":"/pending"},{"label":{"et":"Ajalugu","en":"History"},"path":"/history"},{"label":{"et":"Valideerimised","en":"Validations"},"path":"/validations"}]},{"id":"training","label":{"et":"Treening","en":"Training"},"path":"/training","children":[{"label":{"et":"Treening","en":"Training"},"path":"/training","children":[{"label":{"et":"Teemad","en":"Themes"},"path":"/training/intents"},{"hidden":true,"label":{"et":"Avalikud teemad","en":"Public themes"},"path":"/training/common-intents"},{"label":{"et":"Teemade järeltreenimine","en":"Post training themes"},"path":"/training/intents-followup-training"},{"label":{"et":"Vastused","en":"Answers"},"path":"/training/responses"},{"label":{"et":"Reeglid","en":"Rules"},"path":"/training/rules"},{"hidden":true,"label":{"et":"Konfiguratsioon","en":"Configuration"},"path":"/training/configuration"},{"label":{"et":"Vormid","en":"Forms"},"path":"/training/forms"},{"label":{"et":"Mälukohad","en":"Slots"},"path":"/training/slots"}]},{"label":{"et":"Ajaloolised vestlused","en":"Historical conversations"},"path":"/history","children":[{"label":{"et":"Ajalugu","en":"History"},"path":"/history/history"},{"hidden":true,"label":{"et":"Pöördumised","en":"Appeals"},"path":"/history/appeal"}]},{"label":{"et":"Mudelipank ja analüütika","en":"Modelbank and analytics"},"path":"/analytics","children":[{"label":{"et":"Teemade ülevaade","en":"Overview of topics"},"path":"/analytics/overview"},{"label":{"et":"Mudelite võrdlus","en":"Comparison of models"},"path":"/analytics/models"},{"hidden":true,"label":{"et":"Testlood","en":"testTracks"},"path":"/analytics/testcases"}]},{"label":{"et":"Treeni uus mudel","en":"Train new model"},"path":"/train-new-model"}]},{"id":"analytics","label":{"et":"Analüütika","en":"Analytics"},"path":"/analytics","children":[{"label":{"et":"Ülevaade","en":"Overview"},"path":"/overview"},{"label":{"et":"Vestlused","en":"Chats"},"path":"/chats"},{"label":{"et":"Tagasiside","en":"Feedback"},"path":"/feedback"},{"label":{"et":"Avaandmed","en":"Reports"},"path":"/reports"}]},{"id":"services","hidden":true,"label":{"et":"Teenused","en":"Services"},"path":"/services","children":[{"label":{"et":"Ülevaade","en":"Overview"},"path":"/overview"},{"label":{"et":"Uus teenus","en":"New Service"},"path":"/newService"},{"label":{"et":"Probleemsed teenused","en":"Faulty Services"},"path":"/faultyServices"}]},{"id":"knowledge-center","label":{"et":"Teadmuskeskus","en":"Knowledge Center"},"path":"/knowledge-center","children":[{"id":"rag-search","label":{"et":"Mudelid ja seadistused","en":"Models management"},"path":"/rag-search","children":[{"label":{"et":"Mudelite ühendused","en":"LLM connections"},"path":"/llm-connections"},{"label":{"et":"Viiba Seaded","en":"Prompt Configurations"},"path":"/prompt-configurations"},{"label":{"et":"Testi mudelit","en":"Test LLM"},"path":"/test-llm"}]},{"id":"ckb","label":{"et":"Teadmusbaas","en":"Knowledge Base"},"path":"/ckb","children":[{"label":{"et":"Agentuur","en":"Agency"},"path":"/agency"},{"label":{"et":"Aruanded","en":"Reports"},"path":"/reports"},{"label":{"et":"API Integratsioonid","en":"API Integrations"},"path":"/api"}]}]},{"id":"settings","label":{"et":"Haldus","en":"Administration"},"path":"/settings","children":[{"label":{"et":"Kasutajad","en":"Users"},"path":"/users"},{"label":{"et":"Vestlusbot","en":"Chatbot"},"path":"/chatbot","children":[{"label":{"et":"Seaded","en":"Settings"},"path":"/chatbot/settings"},{"label":{"et":"Tervitussõnum","en":"Welcome message"},"path":"/chatbot/welcome-message"},{"label":{"et":"Välimus ja käitumine","en":"Appearance and behavior"},"path":"/chatbot/appearance"},{"label":{"et":"Erakorralised teated","en":"Emergency notices"},"path":"/chatbot/emergency-notices"},{"label":{"et":"Tagasiside","en":"Feedback"},"path":"/chatbot/feedback"}]},{"label":{"et":"Vestluste analüüs","en":"Chat analysis"},"path":"/chat-analysis"},{"label":{"et":"Asutuse tööaeg","en":"Office opening hours"},"path":"/working-time"},{"label":{"et":"Vestluse Kustutamine","en":"Delete Conversations"},"path":"/delete-conversations"},{"label":{"et":"Sessiooni pikkus","en":"Session length"},"path":"/session-length"},{"label":{"et":"SKMi konfiguratsioon","en":"SKM Configuration"},"path":"/skm-configuration"},{"label":{"et":"Anonümiseerija","en":"Anonymizer"},"path":"/anonymizer"}]},{"id":"monitoring","hidden":true,"label":{"et":"Seire","en":"Monitoring"},"path":"/monitoring","children":[{"label":{"et":"Aktiivaeg","en":"Working hours"},"path":"/uptime"}]}] - VITE_HOST=0.0.0.0 - VITE_PORT=3001 - HOST=0.0.0.0