@cognizant-ai-lab/ui-common 1.6.0 → 1.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. package/dist/Theme/Palettes.d.ts +0 -9
  2. package/dist/Theme/Palettes.js +0 -18
  3. package/dist/components/AgentChat/ChatCommon/ChatCommon.d.ts +11 -7
  4. package/dist/components/AgentChat/ChatCommon/ChatCommon.js +119 -90
  5. package/dist/components/AgentChat/ChatCommon/Const.d.ts +1 -0
  6. package/dist/components/AgentChat/ChatCommon/Const.js +2 -0
  7. package/dist/components/AgentChat/ChatCommon/ControlButtons.d.ts +1 -1
  8. package/dist/components/AgentChat/ChatCommon/ControlButtons.js +7 -4
  9. package/dist/components/AgentChat/ChatCommon/FormattedMarkdown.js +3 -0
  10. package/dist/components/AgentChat/ChatCommon/SendButton.js +7 -6
  11. package/dist/components/AgentChat/ChatCommon/SyntaxHighlighterThemes.js +1 -1
  12. package/dist/components/AgentChat/ChatCommon/Thinking.d.ts +1 -0
  13. package/dist/components/AgentChat/ChatCommon/Thinking.js +10 -7
  14. package/dist/components/AgentChat/Common/LlmChatButton.d.ts +0 -2
  15. package/dist/components/AgentChat/Common/LlmChatButton.js +6 -9
  16. package/dist/components/AgentChat/VoiceChat/MicrophoneButton.js +12 -10
  17. package/dist/components/ChatBot/ChatBot.d.ts +0 -4
  18. package/dist/components/ChatBot/ChatBot.js +2 -2
  19. package/dist/components/Common/Navbar.js +24 -22
  20. package/dist/components/Common/StatusLight.d.ts +9 -0
  21. package/dist/components/Common/StatusLight.js +21 -0
  22. package/dist/components/ErrorPage/ErrorBoundary.js +1 -1
  23. package/dist/components/ErrorPage/ErrorPage.d.ts +3 -3
  24. package/dist/components/ErrorPage/ErrorPage.js +4 -3
  25. package/dist/components/Logo/Common.d.ts +4 -0
  26. package/dist/components/Logo/Common.js +8 -0
  27. package/dist/components/Logo/CustomerLogo.d.ts +23 -0
  28. package/dist/components/Logo/CustomerLogo.js +41 -0
  29. package/dist/components/MultiAgentAccelerator/AgentConversations.js +0 -1
  30. package/dist/components/MultiAgentAccelerator/AgentFlow.js +85 -53
  31. package/dist/components/MultiAgentAccelerator/AgentNode.js +23 -27
  32. package/dist/components/MultiAgentAccelerator/GraphLayouts.d.ts +17 -10
  33. package/dist/components/MultiAgentAccelerator/GraphLayouts.js +4 -6
  34. package/dist/components/MultiAgentAccelerator/MultiAgentAccelerator.d.ts +3 -9
  35. package/dist/components/MultiAgentAccelerator/MultiAgentAccelerator.js +102 -47
  36. package/dist/components/MultiAgentAccelerator/Sidebar/AgentNetworkTreeItem.d.ts +0 -5
  37. package/dist/components/MultiAgentAccelerator/Sidebar/AgentNetworkTreeItem.js +30 -25
  38. package/dist/components/MultiAgentAccelerator/Sidebar/Sidebar.d.ts +3 -4
  39. package/dist/components/MultiAgentAccelerator/Sidebar/Sidebar.js +84 -168
  40. package/dist/components/MultiAgentAccelerator/Sidebar/TreeBuilder.d.ts +30 -13
  41. package/dist/components/MultiAgentAccelerator/Sidebar/TreeBuilder.js +157 -100
  42. package/dist/components/MultiAgentAccelerator/Tour/MainTourSteps.js +10 -8
  43. package/dist/components/MultiAgentAccelerator/const.d.ts +2 -0
  44. package/dist/components/MultiAgentAccelerator/const.js +4 -0
  45. package/dist/components/Settings/ApiKeyInput.d.ts +16 -0
  46. package/dist/components/Settings/ApiKeyInput.js +69 -0
  47. package/dist/components/Settings/InfoTip.d.ts +8 -0
  48. package/dist/components/Settings/InfoTip.js +14 -0
  49. package/dist/components/Settings/SettingsDialog.js +379 -178
  50. package/dist/components/Settings/SettingsRow.d.ts +18 -0
  51. package/dist/components/Settings/SettingsRow.js +35 -0
  52. package/dist/controller/agent/Agent.d.ts +3 -20
  53. package/dist/controller/agent/Agent.js +9 -43
  54. package/dist/controller/agent/IconSuggestions.d.ts +35 -0
  55. package/dist/controller/agent/IconSuggestions.js +85 -0
  56. package/dist/controller/llm/Providers.d.ts +2 -0
  57. package/dist/controller/llm/Providers.js +41 -0
  58. package/dist/index.d.ts +0 -2
  59. package/dist/index.js +0 -2
  60. package/dist/state/IconSuggestions.d.ts +27 -0
  61. package/dist/state/IconSuggestions.js +50 -0
  62. package/dist/state/Settings.d.ts +19 -3
  63. package/dist/state/Settings.js +24 -1
  64. package/dist/tsconfig.build.tsbuildinfo +1 -1
  65. package/dist/utils/title.js +1 -1
  66. package/package.json +5 -1
  67. package/dist/components/Common/CustomerLogo.d.ts +0 -17
  68. package/dist/components/Common/CustomerLogo.js +0 -49
  69. package/dist/components/Common/MUIAccordion.d.ts +0 -17
  70. package/dist/components/Common/MUIAccordion.js +0 -66
  71. package/dist/utils/useLocalStorage.d.ts +0 -1
  72. package/dist/utils/useLocalStorage.js +0 -55
@@ -15,14 +15,15 @@ See the License for the specific language governing permissions and
15
15
  limitations under the License.
16
16
  */
17
17
  import SendIcon from "@mui/icons-material/Send";
18
+ import Tooltip from "@mui/material/Tooltip";
18
19
  import { LlmChatButton } from "../Common/LlmChatButton.js";
19
- // #endregion: Types
20
+ //#endregion: Types
20
21
  /**
21
22
  * Generate the Send Button for a chat window.
22
23
  * @returns The Send Button.
23
24
  */
24
- export const SendButton = ({ enableSendButton, id, onClickCallback }) => (_jsx(LlmChatButton, { "aria-label": "Send", disabled: !enableSendButton, id: id, onClick: onClickCallback, sx: {
25
- padding: "0.6rem",
26
- position: "relative",
27
- }, tabIndex: 0, children: _jsx(SendIcon, { fontSize: "small", id: "stop-button-icon" // Could update this but it would impact QA
28
- , sx: { color: "var(--bs-white)" } }) }));
25
+ export const SendButton = ({ enableSendButton, id, onClickCallback }) => (_jsx(Tooltip, { placement: "top", title: enableSendButton ? "Send" : "Enter a message to enable the send button", children: _jsx("span", { style: {
26
+ display: "inline-block",
27
+ cursor: enableSendButton ? "inherit" : "not-allowed",
28
+ }, children: _jsx(LlmChatButton, { "aria-label": "Send", disabled: !enableSendButton, id: id, onClick: onClickCallback, tabIndex: 0, children: _jsx(SendIcon, { fontSize: "small", id: "stop-button-icon" // Could update this but it would impact QA
29
+ }) }) }) }));
@@ -17,7 +17,7 @@ limitations under the License.
17
17
  * List of available hljs themes for the syntax highlighter.
18
18
  * See: https://github.com/react-syntax-highlighter/react-syntax-highlighter/blob/master/src/styles/hljs/index.js
19
19
  */
20
- import { a11yDark, a11yLight, atelierDuneDark, docco } from "react-syntax-highlighter/dist/cjs/styles/hljs/index.js";
20
+ import { a11yDark, a11yLight, atelierDuneDark, docco } from "react-syntax-highlighter/dist/esm/styles/hljs";
21
21
  // hljs themes
22
22
  export const HLJS_THEMES = {
23
23
  a11yDark,
@@ -3,6 +3,7 @@ import { ConversationTurn } from "./ConversationTurn.js";
3
3
  interface ThinkingProps {
4
4
  readonly id: string;
5
5
  readonly turns: ConversationTurn[];
6
+ readonly useNativeNames: boolean;
6
7
  }
7
8
  /**
8
9
  * Component to render the "thinking" section of the chat, which includes all messages from the agent that are
@@ -6,6 +6,7 @@ import ReactMarkdown from "react-markdown";
6
6
  import { MessageRole } from "./ConversationTurn.js";
7
7
  import { ChatMessageType } from "../../../generated/neuro-san/NeuroSanClient.js";
8
8
  import { AccordionLite } from "../../Common/AccordionLite.js";
9
+ import { cleanUpAgentName, removeTrailingUuid } from "../Common/Utils.js";
9
10
  /**
10
11
  * Set of message types that should be included in the "thinking" section.
11
12
  */
@@ -15,17 +16,19 @@ const THINKING_MESSAGE_TYPES = new Set([
15
16
  ChatMessageType.AGENT_PROGRESS,
16
17
  ChatMessageType.SYSTEM,
17
18
  ]);
18
- const DEFAULT_AGENT_NAME = "Agent";
19
- const formatTurn = (turn) => {
20
- const headerLine = `**${turn.agentName ?? DEFAULT_AGENT_NAME}**: ${turn.text || ""}`;
21
- const structureLine = turn.structure != null ? `\n\`${JSON.stringify(turn.structure, null, 2)}\`` : "";
19
+ const DEFAULT_AGENT_NAME = "agent";
20
+ const formatTurn = (turn, useNativeNames) => {
21
+ const agentName = turn.agentName ?? DEFAULT_AGENT_NAME;
22
+ const displayName = useNativeNames ? agentName : cleanUpAgentName(removeTrailingUuid(agentName));
23
+ const headerLine = `**${displayName}**: ${turn.text || ""}`;
24
+ const structureLine = turn.structure == null ? "" : `\n\`${JSON.stringify(turn.structure, null, 2)}\``;
22
25
  return `${headerLine}${structureLine}`;
23
26
  };
24
27
  /**
25
28
  * Component to render the "thinking" section of the chat, which includes all messages from the agent that are
26
29
  * of a type included in THINKING_MESSAGE_TYPES.
27
30
  */
28
- export const Thinking = ({ id, turns }) => {
31
+ export const Thinking = ({ id, turns, useNativeNames }) => {
29
32
  const thinkingText = useMemo(() => {
30
33
  // Find start of latest interaction (most recent user prompt)
31
34
  const lastUserTurnIndex = turns.map((t) => t.role).lastIndexOf(MessageRole.User);
@@ -35,9 +38,9 @@ export const Thinking = ({ id, turns }) => {
35
38
  .slice(lastUserTurnIndex + 1)
36
39
  .filter((turn) => THINKING_MESSAGE_TYPES.has(turn.messageType))
37
40
  .filter((turn) => turn.text?.trim().length > 0 || !isEmpty(turn.structure))
38
- .map((turn) => formatTurn(turn))
41
+ .map((turn) => formatTurn(turn, useNativeNames))
39
42
  .join("\n\n");
40
- }, [turns]);
43
+ }, [turns, useNativeNames]);
41
44
  return (thinkingText.length > 0 && (_jsx(AccordionLite, { id: `${id}-thinking`, items: _jsx(Box, { sx: {
42
45
  marginLeft: "0.5rem",
43
46
  fontSize: "smaller",
@@ -1,7 +1,5 @@
1
1
  type LLMChatGroupConfigBtnProps = {
2
2
  disabled?: boolean;
3
- posRight?: number;
4
- posBottom?: number;
5
3
  };
6
4
  export declare const LlmChatButton: import("@emotion/styled").StyledComponent<import("@mui/material/Button").ButtonOwnProps & Omit<import("@mui/material/ButtonBase").ButtonBaseOwnProps, keyof import("@mui/material/Button").ButtonOwnProps> & Omit<import("@mui/material/ButtonBase").ButtonBaseOwnProps, "tabIndex" | "type" | "action" | "centerRipple" | "disableRipple" | "disableTouchRipple" | "focusRipple" | "focusVisibleClassName" | "LinkComponent" | "nativeButton" | "onFocusVisible" | "TouchRippleProps" | "touchRippleRef" | keyof import("@mui/material/Button").ButtonOwnProps> & import("@mui/material/OverridableComponent").CommonProps & Omit<import("react").DetailedHTMLProps<import("react").ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>, "style" | "children" | "sx" | "className" | "tabIndex" | "color" | "href" | "type" | "classes" | "variant" | "action" | "size" | "disabled" | "centerRipple" | "disableRipple" | "disableTouchRipple" | "focusRipple" | "focusVisibleClassName" | "LinkComponent" | "nativeButton" | "onFocusVisible" | "TouchRippleProps" | "touchRippleRef" | "disableFocusRipple" | "loading" | "loadingIndicator" | "disableElevation" | "endIcon" | "fullWidth" | "loadingPosition" | "startIcon"> & import("@mui/system").MUIStyledCommonProps<import("@mui/material/styles").Theme> & LLMChatGroupConfigBtnProps, {}, {}>;
7
5
  export declare const SmallLlmChatButton: import("@emotion/styled").StyledComponent<import("@mui/material/Button").ButtonOwnProps & Omit<import("@mui/material/ButtonBase").ButtonBaseOwnProps, keyof import("@mui/material/Button").ButtonOwnProps> & Omit<import("@mui/material/ButtonBase").ButtonBaseOwnProps, "tabIndex" | "type" | "action" | "centerRipple" | "disableRipple" | "disableTouchRipple" | "focusRipple" | "focusVisibleClassName" | "LinkComponent" | "nativeButton" | "onFocusVisible" | "TouchRippleProps" | "touchRippleRef" | keyof import("@mui/material/Button").ButtonOwnProps> & import("@mui/material/OverridableComponent").CommonProps & Omit<import("react").DetailedHTMLProps<import("react").ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>, "style" | "children" | "sx" | "className" | "tabIndex" | "color" | "href" | "type" | "classes" | "variant" | "action" | "size" | "disabled" | "centerRipple" | "disableRipple" | "disableTouchRipple" | "focusRipple" | "focusVisibleClassName" | "LinkComponent" | "nativeButton" | "onFocusVisible" | "TouchRippleProps" | "touchRippleRef" | "disableFocusRipple" | "loading" | "loadingIndicator" | "disableElevation" | "endIcon" | "fullWidth" | "loadingPosition" | "startIcon"> & import("@mui/system").MUIStyledCommonProps<import("@mui/material/styles").Theme> & LLMChatGroupConfigBtnProps, {}, {}>;
@@ -15,17 +15,14 @@ limitations under the License.
15
15
  */
16
16
  import Button from "@mui/material/Button";
17
17
  import { styled } from "@mui/material/styles";
18
- // #endregion: Types
19
- export const LlmChatButton = styled(Button, {
20
- shouldForwardProp: (prop) => !["posRight", "posBottom"].includes(String(prop)),
21
- })(({ theme, disabled, posRight, posBottom }) => ({
22
- background: `${theme.palette.primary.main} !important`,
18
+ //#endregion: Types
19
+ // In LlmChatButton.tsx
20
+ export const LlmChatButton = styled(Button)(({ disabled, theme }) => ({
21
+ backgroundColor: theme.palette.background.paper,
23
22
  borderRadius: "var(--bs-border-radius)",
24
- bottom: posBottom !== undefined ? posBottom : 0,
25
- cursor: disabled ? "default" : "pointer",
23
+ cursor: disabled ? "not-allowed" : "pointer",
26
24
  opacity: disabled ? "50%" : "100%",
27
- right: posRight !== undefined ? posRight : 0,
28
- position: "absolute",
25
+ padding: "0.5rem",
29
26
  }));
30
27
  export const SmallLlmChatButton = styled(LlmChatButton)({
31
28
  minWidth: 0,
@@ -19,7 +19,7 @@ import MicOffIcon from "@mui/icons-material/MicOff";
19
19
  import Tooltip from "@mui/material/Tooltip";
20
20
  import { checkSpeechSupport, toggleListening } from "./VoiceChat.js";
21
21
  import { LlmChatButton } from "../Common/LlmChatButton.js";
22
- // #endregion: Types
22
+ //#endregion: Types
23
23
  /**
24
24
  * Microphone button component for voice input functionality.
25
25
  * Handles toggling voice recognition on/off and displays appropriate visual feedback.
@@ -42,14 +42,16 @@ export const MicrophoneButton = ({ isMicOn, onMicToggle, speechRecognitionRef, v
42
42
  await toggleListening(newMicState, speechRecognitionRef.current);
43
43
  };
44
44
  const isDisabled = !speechSupported;
45
- const tooltipText = !speechSupported
46
- ? "Voice input is only supported in Google Chrome on Mac or Windows."
47
- : isMicOn
45
+ const tooltipText = speechSupported
46
+ ? isMicOn
48
47
  ? "Turn microphone off"
49
- : "Turn microphone on";
50
- return (_jsx(Tooltip, { title: tooltipText, children: _jsx("span", { style: { display: "inline-block", height: 50, width: 64 }, children: _jsx(LlmChatButton, { "data-testid": "microphone-button", disabled: isDisabled, id: "microphone-button", onClick: handleClick, sx: {
51
- padding: "0.5rem",
52
- right: 70,
53
- backgroundColor: isMicOn && voiceInputState.isListening ? "var(--bs-success)" : "var(--bs-secondary)",
54
- }, tabIndex: 0, children: voiceInputState.isListening ? (_jsx(MicNoneIcon, { sx: { color: "var(--bs-white)" }, "data-testid": "MicNoneIcon" })) : (_jsx(MicOffIcon, { sx: { color: "var(--bs-white)" }, "data-testid": "MicOffIcon" })) }) }) }));
48
+ : "Turn microphone on"
49
+ : "Voice input is only supported in Google Chrome on Mac or Windows.";
50
+ const isListeningActive = isMicOn && voiceInputState.isListening;
51
+ return (_jsx(Tooltip, { placement: "top", title: tooltipText, children: _jsx("span", { style: {
52
+ display: "inline-block",
53
+ cursor: isDisabled ? "not-allowed" : "inherit",
54
+ }, children: _jsx(LlmChatButton, { "data-testid": "microphone-button", disabled: isDisabled, id: "microphone-button", onClick: handleClick, sx: {
55
+ backgroundColor: isListeningActive ? "success.main" : "background.paper",
56
+ }, tabIndex: 0, children: voiceInputState.isListening ? (_jsx(MicNoneIcon, { "data-testid": "MicNoneIcon", fontSize: "small" })) : (_jsx(MicOffIcon, { "data-testid": "MicOffIcon", fontSize: "small" })) }) }) }));
55
57
  };
@@ -4,10 +4,6 @@ interface ChatBotProps {
4
4
  * id HTML id to use for the outer component
5
5
  */
6
6
  readonly id: string;
7
- /**
8
- * Path to image for user avatar
9
- */
10
- readonly userAvatar: string;
11
7
  /**
12
8
  * Text about current page to help the LLM respond intelligently
13
9
  */
@@ -29,7 +29,7 @@ import { LegacyAgentType } from "../AgentChat/Common/Types.js";
29
29
  * Site-wide Chatbot component.
30
30
  */
31
31
  // Temporarily disabled but will be used once we migrated the backend to use Neuro-san RAG.
32
- export const ChatBot = ({ id, userAvatar, pageContext }) => {
32
+ export const ChatBot = ({ id, pageContext }) => {
33
33
  const [chatOpen, setChatOpen] = useState(false);
34
34
  const [isAwaitingLlm, setIsAwaitingLlm] = useState(false);
35
35
  const { user: { name: currentUser }, } = useAuthentication().data;
@@ -51,7 +51,7 @@ export const ChatBot = ({ id, userAvatar, pageContext }) => {
51
51
  borderWidth: 1,
52
52
  borderColor: darkMode ? "var(--bs-white)" : "var(--bs-gray-light)",
53
53
  zIndex: getZIndex(2, theme),
54
- }, children: _jsx(ChatCommon, { id: "chatbot-window", currentUser: currentUser, setIsAwaitingLlm: setIsAwaitingLlm, isAwaitingLlm: isAwaitingLlm, targetAgent: LegacyAgentType.ChatBot, userImage: userAvatar, legacyAgentEndpoint: CHATBOT_ENDPOINT, extraParams: { pageContext }, backgroundColor: darkMode ? "var(--bs-gray-dark)" : "var(--bs-tertiary-blue)", title: "Cognizant Neuro AI Assistant", onClose: () => setChatOpen(false) }) }) }), !chatOpen && (_jsx(Box, { id: `chatbot-icon-${id}`, sx: {
54
+ }, children: _jsx(ChatCommon, { id: "chatbot-window", currentUser: currentUser, setIsAwaitingLlm: setIsAwaitingLlm, isAwaitingLlm: isAwaitingLlm, selectedNetwork: LegacyAgentType.ChatBot, legacyAgentEndpoint: CHATBOT_ENDPOINT, extraParams: { pageContext }, backgroundColor: darkMode ? "var(--bs-gray-dark)" : "var(--bs-tertiary-blue)", title: "Cognizant Neuro AI Assistant", onClose: () => setChatOpen(false) }) }) }), !chatOpen && (_jsx(Box, { id: `chatbot-icon-${id}`, sx: {
55
55
  display: "flex",
56
56
  alignItems: "center",
57
57
  backgroundColor: darkMode ? "var(--bs-dark-mode-dim)" : "var(--bs-white)",
@@ -1,4 +1,4 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
1
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  /*
3
3
  Copyright 2025 Cognizant Technology Solutions Corp, www.cognizant.com.
4
4
 
@@ -18,6 +18,7 @@ limitations under the License.
18
18
  * Main navigation bar that appears at the top of each page
19
19
  */
20
20
  import ArrowDropDownIcon from "@mui/icons-material/ArrowDropDown";
21
+ import Business from "@mui/icons-material/Business";
21
22
  import DarkModeIcon from "@mui/icons-material/DarkMode";
22
23
  import SettingsIcon from "@mui/icons-material/Settings";
23
24
  import Box from "@mui/material/Box";
@@ -28,14 +29,14 @@ import MenuItem from "@mui/material/MenuItem";
28
29
  import { useColorScheme } from "@mui/material/styles";
29
30
  import Tooltip from "@mui/material/Tooltip";
30
31
  import Typography from "@mui/material/Typography";
31
- import { useEffect, useState } from "react";
32
+ import { useState } from "react";
32
33
  import { ConfirmationModal } from "./ConfirmationModal.js";
33
- import { CustomerLogo, getCognizantLogoImage } from "./CustomerLogo.js";
34
- import { LoadingSpinner } from "./LoadingSpinner.js";
35
34
  import { authenticationEnabled, DEFAULT_USER_IMAGE, getContactUsConfirmationText, NEURO_SAN_UI_VERSION, } from "../../const.js";
36
35
  import { useSettingsStore } from "../../state/Settings.js";
37
36
  import { isDarkMode } from "../../Theme/Theme.js";
38
37
  import { navigateToUrl } from "../../utils/BrowserNavigation.js";
38
+ import { getCognizantLogoImage } from "../Logo/Common.js";
39
+ import { CustomerLogo } from "../Logo/CustomerLogo.js";
39
40
  import { SettingsDialog } from "../Settings/SettingsDialog.js";
40
41
  const MENU_ITEM_TEXT_PROPS = {
41
42
  color: "var(--bs-white)",
@@ -58,12 +59,6 @@ export const Navbar = ({ authenticationType, id, logo, logoServiceToken, onStart
58
59
  // Dark mode
59
60
  const { mode, setMode, systemMode } = useColorScheme();
60
61
  const darkMode = isDarkMode(mode, systemMode);
61
- // Gate to make sure we only attempt to render after Next.js has completed its rehydration
62
- const [hydrated, setHydrated] = useState(false);
63
- useEffect(() => {
64
- // Indicate that the component has been hydrated
65
- setHydrated(true);
66
- }, []);
67
62
  // Help menu wiring
68
63
  const [helpMenuAnchorEl, setHelpMenuAnchorEl] = useState(null);
69
64
  const helpMenuOpen = Boolean(helpMenuAnchorEl);
@@ -88,18 +83,25 @@ export const Navbar = ({ authenticationType, id, logo, logoServiceToken, onStart
88
83
  const customer = useSettingsStore((state) => state.settings.branding.customer);
89
84
  const primary = useSettingsStore((state) => state.settings.branding.primary);
90
85
  const hasCustomer = customer?.trim().length > 0;
91
- return hydrated ? (_jsxs(Grid, { id: "nav-bar-container", container: true, sx: {
86
+ // Logo settings
87
+ const iconSuggestion = useSettingsStore((state) => state.settings.branding.iconSuggestion);
88
+ const logoSource = useSettingsStore((state) => state.settings.branding.logoSource);
89
+ return (_jsxs(Grid, { id: "nav-bar-container", container: true, sx: {
92
90
  alignItems: "center",
93
91
  ...MENU_ITEM_TEXT_PROPS,
94
92
  padding: "0.5rem",
95
- }, children: [settingsDialogOpen && (_jsx(SettingsDialog, { id: "settings-dialog", isOpen: settingsDialogOpen, logoServiceToken: logoServiceToken, onClose: () => setSettingsDialogOpen(false) })), _jsxs(Box, { sx: { display: "flex", alignItems: "center", gap: 2 }, children: [_jsx(CustomerLogo, { logoServiceToken: logoServiceToken }), hasCustomer && (_jsx(Typography, { "data-testid": "customer-branding", sx: {
96
- fontSize: "20px",
97
- fontWeight: "600",
98
- paddingLeft: "0.15rem",
99
- width: "200px",
100
- display: "flex",
101
- alignItems: "center",
102
- }, children: customer }))] }), _jsxs(Grid, { id: id, sx: { display: "flex", alignItems: "center" }, children: [hasCustomer ? getCognizantLogoImage() : null, _jsx(Typography, { id: "nav-bar-brand", sx: {
93
+ }, children: [settingsDialogOpen && (_jsx(SettingsDialog, { id: "settings-dialog", isOpen: settingsDialogOpen, logoServiceToken: logoServiceToken, onClose: () => setSettingsDialogOpen(false) })), _jsx(Box, { sx: {
94
+ alignItems: "center",
95
+ display: "flex",
96
+ gap: 2,
97
+ }, children: hasCustomer ? (_jsxs(_Fragment, { children: [_jsx(CustomerLogo, { customer: customer, fallbackIcon: Business, iconSuggestion: iconSuggestion, logoServiceToken: logoServiceToken, logoSource: logoSource }), _jsx(Typography, { "data-testid": "customer-branding", sx: {
98
+ fontSize: "20px",
99
+ fontWeight: "600",
100
+ paddingLeft: "0.15rem",
101
+ width: "200px",
102
+ display: "flex",
103
+ alignItems: "center",
104
+ }, children: customer })] })) : (getCognizantLogoImage()) }), _jsxs(Grid, { id: id, sx: { display: "flex", alignItems: "center" }, children: [hasCustomer ? getCognizantLogoImage() : null, _jsx(Typography, { id: "nav-bar-brand", sx: {
103
105
  ...MENU_ITEM_TEXT_PROPS,
104
106
  marginLeft: "0.85rem",
105
107
  fontSize: "16px",
@@ -125,13 +127,13 @@ export const Navbar = ({ authenticationType, id, logo, logoServiceToken, onStart
125
127
  alignItems: "center",
126
128
  }, onClick: (event) => {
127
129
  setExploreMenuAnchorEl(event.currentTarget);
128
- }, children: ["Explore", _jsx(ArrowDropDownIcon, { id: "nav-explore-dropdown-arrow", sx: { color: primary || "var(--bs-white)", fontSize: 22 } })] }), _jsxs(Menu, { id: "explore-menu", anchorEl: exploreMenuAnchorEl, open: exploreMenuOpen, onClose: handleCloseExploreMenu, children: [_jsx(MenuItem, { id: "explore-neuro-san-studio", component: "a", href: "https://github.com/cognizant-ai-lab/neuro-san-studio", target: "_blank", sx: { ...DISABLE_OUTLINE_PROPS }, children: "Neuro-san studio (examples)" }, "explore-neuro-san-studio"), _jsx(MenuItem, { id: "explore-neuro-san", component: "a", href: "https://github.com/cognizant-ai-lab/neuro-san", target: "_blank", sx: { ...DISABLE_OUTLINE_PROPS }, children: "Neuro-san (core)" }, "explore-neuro-san")] })] }), _jsxs(Grid, { id: "help-dropdown", sx: { cursor: "pointer", marginRight: "30px" }, children: [_jsxs(Typography, { id: "help-toggle", sx: {
130
+ }, children: ["Explore", _jsx(ArrowDropDownIcon, { id: "nav-explore-dropdown-arrow", sx: { color: primary || "var(--bs-white)", fontSize: 22 } })] }), _jsxs(Menu, { id: "explore-menu", anchorEl: exploreMenuAnchorEl, open: exploreMenuOpen, onClose: handleCloseExploreMenu, children: [_jsx(MenuItem, { id: "explore-neuro-san-studio", component: "a", href: "https://github.com/cognizant-ai-lab/neuro-san-studio", rel: "noopener noreferrer", sx: { ...DISABLE_OUTLINE_PROPS }, target: "_blank", children: "Neuro-san studio (examples)" }, "explore-neuro-san-studio"), _jsx(MenuItem, { id: "explore-neuro-san", component: "a", href: "https://github.com/cognizant-ai-lab/neuro-san", rel: "noopener noreferrer", sx: { ...DISABLE_OUTLINE_PROPS }, target: "_blank", children: "Neuro-san (core)" }, "explore-neuro-san")] })] }), _jsxs(Grid, { id: "help-dropdown", sx: { cursor: "pointer", marginRight: "30px" }, children: [_jsxs(Typography, { id: "help-toggle", sx: {
129
131
  ...MENU_ITEM_TEXT_PROPS,
130
132
  display: "flex",
131
133
  alignItems: "center",
132
134
  }, onClick: (event) => {
133
135
  setHelpMenuAnchorEl(event.currentTarget);
134
- }, children: ["Help", _jsx(ArrowDropDownIcon, { id: "nav-help-dropdown-arrow", sx: { color: primary || "var(--bs-white)", fontSize: 22 } })] }), _jsxs(Menu, { id: "help-menu", anchorEl: helpMenuAnchorEl, open: helpMenuOpen, onClose: handleCloseHelpMenu, children: [_jsx(MenuItem, { id: "user-guide", component: "a", href: "/userguide", target: "_blank", sx: { ...DISABLE_OUTLINE_PROPS }, children: "User guide" }, "user-guide"), _jsx(MenuItem, { id: "take-a-tour", onClick: () => {
136
+ }, children: ["Help", _jsx(ArrowDropDownIcon, { id: "nav-help-dropdown-arrow", sx: { color: primary || "var(--bs-white)", fontSize: 22 } })] }), _jsxs(Menu, { id: "help-menu", anchorEl: helpMenuAnchorEl, open: helpMenuOpen, onClose: handleCloseHelpMenu, children: [_jsx(MenuItem, { id: "user-guide", component: "a", href: "/UserGuide", rel: "noopener noreferrer", sx: { ...DISABLE_OUTLINE_PROPS }, target: "_blank", children: "User guide" }, "user-guide"), _jsx(MenuItem, { id: "take-a-tour", onClick: () => {
135
137
  handleCloseHelpMenu();
136
138
  onStartTour?.();
137
139
  }, sx: { ...DISABLE_OUTLINE_PROPS }, children: "Take a tour" }, "take-a-tour"), _jsx(MenuItem, { href: null, id: "contact-us-help", onClick: () => setEmailDialogOpen(true), children: "Contact Us" }, "contact-us-help")] })] }), emailDialogOpen ? (_jsx(ConfirmationModal, { id: "email-dialog", content: getContactUsConfirmationText(supportEmailAddress), handleCancel: () => {
@@ -163,5 +165,5 @@ export const Navbar = ({ authenticationType, id, logo, logoServiceToken, onStart
163
165
  cursor: "pointer",
164
166
  }, onClick: () => {
165
167
  setSettingsDialogOpen(true);
166
- } }) }))] })) : (_jsx(LoadingSpinner, { id: "navbar-loading-spinner" }));
168
+ } }) }))] }));
167
169
  };
@@ -0,0 +1,9 @@
1
+ import { FC, ReactElement } from "react";
2
+ type Status = "green" | "red" | "unknown";
3
+ interface StatusLightProps {
4
+ readonly id?: string;
5
+ readonly statusValue: Status;
6
+ readonly tooltip?: ReactElement;
7
+ }
8
+ export declare const StatusLight: FC<StatusLightProps>;
9
+ export {};
@@ -0,0 +1,21 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import Box from "@mui/material/Box";
3
+ import Tooltip from "@mui/material/Tooltip";
4
+ const statusToColor = (statusValue) => {
5
+ switch (statusValue) {
6
+ case "green":
7
+ return "success.main";
8
+ case "red":
9
+ return "error.main";
10
+ case "unknown":
11
+ default:
12
+ return "action.disabled";
13
+ }
14
+ };
15
+ export const StatusLight = ({ id, statusValue, tooltip }) => (_jsx(Tooltip, { title: tooltip, placement: "top", children: _jsx(Box, { id: id, "data-testid": id, "data-status": statusValue, sx: {
16
+ backgroundColor: statusToColor(statusValue),
17
+ borderRadius: "50%",
18
+ display: "inline-block",
19
+ minWidth: "0.75rem",
20
+ minHeight: "0.75rem",
21
+ } }) }));
@@ -15,7 +15,7 @@ See the License for the specific language governing permissions and
15
15
  limitations under the License.
16
16
  */
17
17
  import { Component } from "react";
18
- import ErrorPage from "./ErrorPage.js";
18
+ import { default as ErrorPage } from "./ErrorPage.js";
19
19
  /**
20
20
  * Implements a system-wide error handler for Next.js pages in our app.
21
21
  * Taken from here: https://nextjs.org/docs/advanced-features/error-handling
@@ -1,4 +1,4 @@
1
- import { ReactElement } from "react";
1
+ import { FC } from "react";
2
2
  interface ErrorPageProps {
3
3
  id: string;
4
4
  errorText: string;
@@ -8,5 +8,5 @@ interface ErrorPageProps {
8
8
  * @param id HTML id for the <code>div</code> for this page
9
9
  * @param errorText Error text to be displayed
10
10
  */
11
- export default function ErrorPage({ id, errorText }: ErrorPageProps): ReactElement;
12
- export {};
11
+ declare const ErrorPage: FC<ErrorPageProps>;
12
+ export default ErrorPage;
@@ -28,9 +28,9 @@ import { Navbar } from "../Common/Navbar.js";
28
28
  * @param id HTML id for the <code>div</code> for this page
29
29
  * @param errorText Error text to be displayed
30
30
  */
31
- export default function ErrorPage({ id, errorText }) {
31
+ const ErrorPage = ({ id, errorText }) => {
32
32
  const { auth0ClientId, auth0Domain, supportEmailAddress, logoServiceToken } = useEnvironmentStore();
33
- // Access NextJS router
33
+ // Access Next.js router
34
34
  const router = useRouter();
35
35
  // Access user info store
36
36
  const { currentUser, setCurrentUser, setPicture, oidcProvider } = useUserInfoStore();
@@ -44,4 +44,5 @@ export default function ErrorPage({ id, errorText }) {
44
44
  await smartSignOut(currentUser, auth0Domain, auth0ClientId, oidcProvider);
45
45
  };
46
46
  return (_jsxs(_Fragment, { children: [_jsx(Navbar, { authenticationType: authenticationType, id: "nav-bar", logo: LOGO, logoServiceToken: logoServiceToken, pathname: router.pathname, query: router.query, signOut: handleSignOut, supportEmailAddress: supportEmailAddress, userInfo: userInfo }), _jsxs(Box, { id: id, sx: { marginLeft: "1rem" }, children: [_jsx(NeuroAIBreadcrumbs, {}), _jsx("h4", { id: "error-header", style: { color: "var(--bs-red)", marginTop: "1rem" }, children: "Oops, an internal error occurred on our end." }), _jsxs("div", { id: "error-div-1", children: [_jsxs(Box, { id: "no-need-to-worry", sx: { marginBottom: "1.5rem" }, children: [_jsx("b", { id: "bold-1", children: "There's no need to worry \u2013 you didn't do anything wrong." }), " This is a bug in our server and we'll fix it as soon as possible."] }), _jsx(Box, { id: "try-these-steps", sx: { marginBottom: "1.5rem" }, children: "To attempt to recover from the error, try these steps:" }), _jsx(Box, { id: "refresh-page", sx: { marginBottom: "1.5rem" }, children: _jsxs("ul", { id: "error-boundary-advice-list", className: "list-decimal list-inside", children: [_jsx("li", { id: "error-advice-refresh", children: "Refresh the page to see if the error goes away." }), _jsx("li", { id: "error-advice-reload", children: "Close and re-open your browser, then navigate back to the page where you encountered the error." })] }) }), "If none of that helps, please report the following error to the LEAF team:"] }), _jsx("div", { id: "error-text-div", style: { fontFamily: "monospace", marginTop: "1.5rem", marginBottom: "1.5rem" }, children: errorText }), "More information may be available in the browser console. Please include such information in your report if possible."] }), _jsx(Footer, { supportEmailAddress: supportEmailAddress, logoLinkUrl: "https://www.cognizant.com/", logoUrl: "/cognizant-logo-white.svg" })] }));
47
- }
47
+ };
48
+ export default ErrorPage;
@@ -0,0 +1,4 @@
1
+ /**
2
+ * Returns the Cognizant logo with a link to the corporate website.
3
+ */
4
+ export declare const getCognizantLogoImage: () => import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,8 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ /**
3
+ * Returns the Cognizant logo with a link to the corporate website.
4
+ */
5
+ export const getCognizantLogoImage = () => (_jsx("a", { id: "splash-logo-link", href: "https://www.cognizant.com/us/en", style: {
6
+ display: "flex",
7
+ paddingLeft: "0.15rem",
8
+ }, target: "_blank", rel: "noopener noreferrer", children: _jsx("img", { id: "logo-img", width: "200", height: "45", src: "/cognizant-logo-white.svg", alt: "Cognizant Logo" }) }));
@@ -0,0 +1,23 @@
1
+ import { SvgIconProps } from "@mui/material/SvgIcon";
2
+ import { FC } from "react";
3
+ import { LogoSource } from "../../state/Settings.js";
4
+ interface CustomerLogoProps {
5
+ readonly customer: string;
6
+ readonly fallbackIcon?: FC<SvgIconProps>;
7
+ readonly iconSuggestion?: string;
8
+ readonly logoServiceToken?: string;
9
+ readonly logoSource: LogoSource;
10
+ }
11
+ export declare const LOGO_DEV_URL = "https://img.logo.dev/name";
12
+ /**
13
+ * Component to display the customer's logo based on the settings.
14
+ * @param customer - Name of the customer, used for fetching the logo from logo.dev when logoSource is "auto"
15
+ * @param fallbackIcon - Optional MUI icon to use as a fallback if other approaches fail
16
+ * @param iconSuggestion - Optional MUI icon name to use when logoSource is "generic"
17
+ * @param logoServiceToken - Optional token for fetching the logo from logo.dev
18
+ * @param logoSource - Source of the logo, determines how the logo is rendered ("none", "generic", or "auto")
19
+ * @returns JSX element representing the customer's logo, MUI icon, or Cognizant fallback, or null if no logo
20
+ * should be displayed or if the logo.dev token is missing/invalid.
21
+ */
22
+ export declare const CustomerLogo: FC<CustomerLogoProps>;
23
+ export {};
@@ -0,0 +1,41 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ // Have to suppress this lint error to allow dynamic access of MUI icons
3
+ // eslint-disable-next-line no-restricted-imports
4
+ import * as MuiIcons from "@mui/icons-material";
5
+ //#endregion
6
+ export const LOGO_DEV_URL = "https://img.logo.dev/name";
7
+ /**
8
+ * Component to display the customer's logo based on the settings.
9
+ * @param customer - Name of the customer, used for fetching the logo from logo.dev when logoSource is "auto"
10
+ * @param fallbackIcon - Optional MUI icon to use as a fallback if other approaches fail
11
+ * @param iconSuggestion - Optional MUI icon name to use when logoSource is "generic"
12
+ * @param logoServiceToken - Optional token for fetching the logo from logo.dev
13
+ * @param logoSource - Source of the logo, determines how the logo is rendered ("none", "generic", or "auto")
14
+ * @returns JSX element representing the customer's logo, MUI icon, or Cognizant fallback, or null if no logo
15
+ * should be displayed or if the logo.dev token is missing/invalid.
16
+ */
17
+ export const CustomerLogo = ({ customer, fallbackIcon: FallbackIcon, iconSuggestion, logoServiceToken, logoSource, }) => {
18
+ const hasCustomer = customer?.trim()?.length > 0;
19
+ const fallback = FallbackIcon ? _jsx(FallbackIcon, { sx: { fontSize: "2rem" } }) : null;
20
+ // "generic": check if suggested MUI icon is valid
21
+ switch (logoSource) {
22
+ case "generic": {
23
+ const MuiIcon = MuiIcons[iconSuggestion];
24
+ const LogoIcon = MuiIcon ?? FallbackIcon;
25
+ return LogoIcon ? _jsx(LogoIcon, { sx: { fontSize: "2rem" } }) : null;
26
+ }
27
+ case "auto": {
28
+ if (!hasCustomer || !logoServiceToken || logoServiceToken.trim().length === 0) {
29
+ return fallback;
30
+ }
31
+ // "auto": use logo.dev service
32
+ // eslint-disable-next-line max-len -- better to keep URL together
33
+ const logoUrl = `${LOGO_DEV_URL}/${encodeURIComponent(customer)}?token=${logoServiceToken}&theme=dark&format=png&size=75`;
34
+ return (_jsx("img", { src: logoUrl, alt: `${customer} Logo`, width: 40, height: 40, style: { borderRadius: "50%" } }));
35
+ }
36
+ case "none":
37
+ return null;
38
+ default:
39
+ return fallback;
40
+ }
41
+ };
@@ -22,7 +22,6 @@ export const isFinalMessage = (chatMessage) => {
22
22
  export const createConversation = (agents, text, type) => ({
23
23
  // Could use crypto.randomUUID, but it's only available under HTTPS, and don't want to use a different
24
24
  // solution for HTTP on localhost.
25
- // eslint-disable-next-line newline-per-chained-call
26
25
  id: `conv_${Date.now()}${Math.random().toString(36).slice(2, 10)}`,
27
26
  agents: new Set(agents),
28
27
  startedAt: new Date(),