@cognizant-ai-lab/ui-common 1.7.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 (67) 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 +4 -1
  4. package/dist/components/AgentChat/ChatCommon/ChatCommon.js +74 -47
  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/Common/Navbar.js +24 -22
  18. package/dist/components/Common/StatusLight.d.ts +9 -0
  19. package/dist/components/Common/StatusLight.js +21 -0
  20. package/dist/components/ErrorPage/ErrorBoundary.js +1 -1
  21. package/dist/components/ErrorPage/ErrorPage.d.ts +3 -3
  22. package/dist/components/ErrorPage/ErrorPage.js +4 -3
  23. package/dist/components/Logo/Common.d.ts +4 -0
  24. package/dist/components/Logo/Common.js +8 -0
  25. package/dist/components/Logo/CustomerLogo.d.ts +23 -0
  26. package/dist/components/Logo/CustomerLogo.js +41 -0
  27. package/dist/components/MultiAgentAccelerator/AgentConversations.js +0 -1
  28. package/dist/components/MultiAgentAccelerator/AgentFlow.js +85 -53
  29. package/dist/components/MultiAgentAccelerator/AgentNode.js +23 -27
  30. package/dist/components/MultiAgentAccelerator/GraphLayouts.d.ts +17 -10
  31. package/dist/components/MultiAgentAccelerator/GraphLayouts.js +4 -6
  32. package/dist/components/MultiAgentAccelerator/MultiAgentAccelerator.d.ts +3 -9
  33. package/dist/components/MultiAgentAccelerator/MultiAgentAccelerator.js +28 -32
  34. package/dist/components/MultiAgentAccelerator/Sidebar/AgentNetworkTreeItem.d.ts +0 -5
  35. package/dist/components/MultiAgentAccelerator/Sidebar/AgentNetworkTreeItem.js +30 -25
  36. package/dist/components/MultiAgentAccelerator/Sidebar/Sidebar.d.ts +3 -4
  37. package/dist/components/MultiAgentAccelerator/Sidebar/Sidebar.js +84 -168
  38. package/dist/components/MultiAgentAccelerator/Sidebar/TreeBuilder.d.ts +30 -13
  39. package/dist/components/MultiAgentAccelerator/Sidebar/TreeBuilder.js +157 -100
  40. package/dist/components/MultiAgentAccelerator/Tour/MainTourSteps.js +10 -8
  41. package/dist/components/MultiAgentAccelerator/const.d.ts +2 -0
  42. package/dist/components/MultiAgentAccelerator/const.js +4 -0
  43. package/dist/components/Settings/ApiKeyInput.js +7 -8
  44. package/dist/components/Settings/InfoTip.d.ts +8 -0
  45. package/dist/components/Settings/InfoTip.js +14 -0
  46. package/dist/components/Settings/SettingsDialog.js +355 -181
  47. package/dist/components/Settings/SettingsRow.d.ts +18 -0
  48. package/dist/components/Settings/SettingsRow.js +35 -0
  49. package/dist/controller/agent/Agent.d.ts +3 -20
  50. package/dist/controller/agent/Agent.js +9 -43
  51. package/dist/controller/agent/IconSuggestions.d.ts +35 -0
  52. package/dist/controller/agent/IconSuggestions.js +85 -0
  53. package/dist/index.d.ts +0 -2
  54. package/dist/index.js +0 -2
  55. package/dist/state/IconSuggestions.d.ts +27 -0
  56. package/dist/state/IconSuggestions.js +50 -0
  57. package/dist/state/Settings.d.ts +17 -3
  58. package/dist/state/Settings.js +23 -1
  59. package/dist/tsconfig.build.tsbuildinfo +1 -1
  60. package/dist/utils/title.js +1 -1
  61. package/package.json +5 -1
  62. package/dist/components/Common/CustomerLogo.d.ts +0 -17
  63. package/dist/components/Common/CustomerLogo.js +0 -47
  64. package/dist/components/Common/MUIAccordion.d.ts +0 -17
  65. package/dist/components/Common/MUIAccordion.js +0 -66
  66. package/dist/utils/useLocalStorage.d.ts +0 -1
  67. package/dist/utils/useLocalStorage.js +0 -55
@@ -15,27 +15,22 @@ See the License for the specific language governing permissions and
15
15
  limitations under the License.
16
16
  */
17
17
  import AddBoxRounded from "@mui/icons-material/AddBoxRounded";
18
- import CheckCircleOutlinedIcon from "@mui/icons-material/CheckCircleOutlined";
19
- import ClearIcon from "@mui/icons-material/Clear";
20
- import HighlightOff from "@mui/icons-material/HighlightOff";
21
- import SettingsIcon from "@mui/icons-material/Settings";
22
18
  import Box from "@mui/material/Box";
23
19
  import Button from "@mui/material/Button";
24
- import IconButton from "@mui/material/IconButton";
25
- import InputAdornment from "@mui/material/InputAdornment";
26
- import Popover from "@mui/material/Popover";
27
- import { keyframes, styled, useTheme } from "@mui/material/styles";
28
- import TextField from "@mui/material/TextField";
29
- import Tooltip from "@mui/material/Tooltip";
20
+ import { keyframes, styled } from "@mui/material/styles";
21
+ import Tooltip, { tooltipClasses } from "@mui/material/Tooltip";
30
22
  import Typography from "@mui/material/Typography";
31
23
  import { RichTreeView } from "@mui/x-tree-view/RichTreeView";
32
- import { useEffect, useState, } from "react";
24
+ import httpStatus from "http-status";
25
+ import { useEffect, useState } from "react";
33
26
  import { AgentNetworkTreeItem } from "./AgentNetworkTreeItem.js";
34
- import { buildTreeViewItems } from "./TreeBuilder.js";
27
+ import { buildTreeViewItems, findTreeItemById } from "./TreeBuilder.js";
35
28
  import { testConnection } from "../../../controller/agent/Agent.js";
36
- import { useEnvironmentStore } from "../../../state/Environment.js";
29
+ import { useSettingsStore } from "../../../state/Settings.js";
37
30
  import { getZIndex } from "../../../utils/zIndexLayers.js";
31
+ import { StatusLight } from "../../Common/StatusLight.js";
38
32
  import { AGENT_NETWORK_DESIGNER_ID, TEMPORARY_NETWORK_FOLDER } from "../const.js";
33
+ //#region Constants
39
34
  // Animation for the sparkle effect when a new temporary network is added.
40
35
  const sparkle = keyframes `
41
36
  0% {
@@ -71,13 +66,13 @@ const sparkle = keyframes `
71
66
  opacity: 0.25;
72
67
  }
73
68
  `;
74
- // #region: Styled Components
75
- const PrimaryButton = styled(Button)({
76
- marginLeft: "0.5rem",
77
- marginTop: "2px",
78
- });
79
69
  // Name for sparkle animation CSS class
80
70
  export const SPARKLE_HIGHLIGHT_CLASS = "sparkle-highlight";
71
+ const EMPTY_ARRAY = [];
72
+ // Interval for pinging the Neuro-san server to check if it's online, in milliseconds
73
+ const NEURO_SAN_PING_INTERVAL_MS = 30_000;
74
+ //#endregion: Constants
75
+ //#region: Styled Components
81
76
  // Styled component for Sidebar aside element, including styles for the sparkle highlight animation
82
77
  // when a new temporary network is added.
83
78
  const SidebarAside = styled("aside")({
@@ -111,98 +106,48 @@ const SidebarHeading = styled("h2")(({ theme }) => ({
111
106
  top: 0,
112
107
  zIndex: getZIndex(1, theme),
113
108
  }));
114
- // #endregion: Styled Components
115
- // #region: Types
116
- var CONNECTION_STATUS;
117
- (function (CONNECTION_STATUS) {
118
- CONNECTION_STATUS["IDLE"] = "idle";
119
- CONNECTION_STATUS["SUCCESS"] = "success";
120
- CONNECTION_STATUS["ERROR"] = "error";
121
- })(CONNECTION_STATUS || (CONNECTION_STATUS = {}));
122
- // #endregion: Types
123
- const EMPTY_ARRAY = [];
124
- export const Sidebar = ({ customURLCallback, customURLLocalStorage, id, isAwaitingLlm, networkIconSuggestions, networks, newlyAddedTemporaryNetworks, onDeleteNetwork, onEditNetwork, setSelectedNetwork, temporaryNetworks = EMPTY_ARRAY, }) => {
125
- // Get default URL from the environment store.
126
- const { backendNeuroSanApiUrl } = useEnvironmentStore();
127
- const [urlInput, setUrlInput] = useState(customURLLocalStorage || backendNeuroSanApiUrl);
128
- const [connectionStatus, setConnectionStatus] = useState(CONNECTION_STATUS.IDLE);
129
- const [testConnectionResult, setTestConnectionResult] = useState(null);
130
- const connectionStatusSuccess = connectionStatus === CONNECTION_STATUS.SUCCESS;
131
- const connectionStatusError = connectionStatus === CONNECTION_STATUS.ERROR;
132
- const isDefaultUrl = urlInput === backendNeuroSanApiUrl;
133
- const saveEnabled = urlInput && (connectionStatusSuccess || (isDefaultUrl && !connectionStatusError));
134
- const [settingsAnchorEl, setSettingsAnchorEl] = useState(null);
135
- const settingsPopoverOpen = Boolean(settingsAnchorEl);
109
+ // For showing server status which can be lengthy
110
+ const ServerStatusTooltip = styled(({ className, ...props }) => (_jsx(Tooltip, { describeChild: true, ...props, classes: { popper: className } })))({
111
+ [`& .${tooltipClasses.tooltip}`]: {
112
+ backgroundColor: "rgba(97, 97, 97, 1)",
113
+ maxWidth: 500,
114
+ opacity: 1,
115
+ },
116
+ });
117
+ //#endregion: Types
118
+ export const Sidebar = ({ id, isAwaitingLlm, networkIconSuggestions, networks, neuroSanServerURL, newlyAddedTemporaryNetworks, onDeleteNetwork, onEditNetwork, setSelectedNetwork, temporaryNetworks = EMPTY_ARRAY, }) => {
136
119
  const [expandedItems, setExpandedItems] = useState([]);
137
120
  const [selectedItem, setSelectedItem] = useState(null);
138
- // Theming/Dark mode
139
- const darkMode = useTheme().palette.mode === "dark";
140
- const handleSettingsClick = (event) => {
141
- // On open of Settings popover, reset the connection status to idle
142
- setConnectionStatus(CONNECTION_STATUS.IDLE);
143
- setSettingsAnchorEl(event.currentTarget);
144
- };
145
- const handleSettingsClose = (cancel = false) => {
146
- setSettingsAnchorEl(null);
147
- // If the user cancels, reset the custom URL input to the local storage value, or the default URL
148
- if (cancel) {
149
- setUrlInput(customURLLocalStorage || backendNeuroSanApiUrl);
150
- }
151
- };
152
- const handleURLChange = (event) => {
153
- setUrlInput(event.target.value);
154
- // Reset connection check since URL input was changed
155
- setConnectionStatus(CONNECTION_STATUS.IDLE);
156
- };
157
- const handleDefaultSettings = () => {
158
- // Clear input but don't close the popover
159
- setUrlInput(backendNeuroSanApiUrl);
160
- // Reset connection check since URL input was cleared
161
- setConnectionStatus(CONNECTION_STATUS.IDLE);
162
- };
163
- const handleSaveSettings = () => {
164
- let tempUrl = urlInput;
165
- if (tempUrl.endsWith("/")) {
166
- tempUrl = tempUrl.slice(0, -1);
167
- }
168
- if (tempUrl && !tempUrl.startsWith("http://") && !tempUrl.startsWith("https://")) {
169
- tempUrl = `https://${tempUrl}`;
170
- }
171
- // Call setSelectedNetwork(null) otherwise it can cause issues when switching agent networks (i.e. for Save)
172
- setSelectedNetwork(null);
173
- handleSettingsClose();
174
- customURLCallback(tempUrl);
175
- };
176
- const handleSettingsSaveEnterKey = (event) => {
177
- if (event.key === "Enter" && saveEnabled) {
178
- handleSaveSettings();
179
- }
180
- };
181
- const handleTestConnection = async () => {
182
- const result = await testConnection(urlInput);
183
- setTestConnectionResult(result);
184
- if (result.success) {
185
- setConnectionStatus(CONNECTION_STATUS.SUCCESS);
186
- }
187
- else {
188
- setConnectionStatus(CONNECTION_STATUS.ERROR);
189
- }
190
- };
191
- const handleClearInput = () => {
192
- setUrlInput("");
193
- setConnectionStatus(CONNECTION_STATUS.IDLE);
194
- };
195
- // Fetch Neuro-san version on load and whenever the saved URL changes
121
+ // Display option for agent/network names
122
+ const useNativeNames = useSettingsStore((state) => state.settings.appearance.useNativeNames);
123
+ const [neuroSanServerStatus, setNeuroSanServerStatus] = useState({ onlineStatus: "unknown", version: null });
196
124
  useEffect(() => {
197
- const fetchVersion = async () => {
198
- // We aren't really trying to test the connection here, just getting the version.
199
- const result = await testConnection(customURLLocalStorage || backendNeuroSanApiUrl);
200
- if (result.success) {
201
- setTestConnectionResult(result);
125
+ let isCurrentRequest = true;
126
+ const checkStatus = async () => {
127
+ try {
128
+ const result = await testConnection(neuroSanServerURL);
129
+ if (!isCurrentRequest) {
130
+ return;
131
+ }
132
+ setNeuroSanServerStatus(result.success
133
+ ? { onlineStatus: "online", version: result.version }
134
+ : { error: result.status, httpStatus: result.httpStatus, onlineStatus: "offline", version: null });
135
+ }
136
+ catch (error) {
137
+ if (!isCurrentRequest) {
138
+ return;
139
+ }
140
+ const errorString = error instanceof Error ? error.message : String(error);
141
+ setNeuroSanServerStatus({ error: errorString, onlineStatus: "offline", version: null });
202
142
  }
203
143
  };
204
- void fetchVersion();
205
- }, [customURLLocalStorage, backendNeuroSanApiUrl]);
144
+ void checkStatus();
145
+ const intervalId = setInterval(checkStatus, NEURO_SAN_PING_INTERVAL_MS);
146
+ return () => {
147
+ isCurrentRequest = false;
148
+ clearInterval(intervalId);
149
+ };
150
+ }, [neuroSanServerURL]);
206
151
  // When the edit pencil is clicked, select the network first (if not already selected) so the network loads
207
152
  // before entering edit mode — the user shouldn't have to click the network and then click the pencil separately.
208
153
  const handleEditNetworkWithSelect = (network) => {
@@ -212,26 +157,21 @@ export const Sidebar = ({ customURLCallback, customURLLocalStorage, id, isAwaiti
212
157
  }
213
158
  onEditNetwork?.(network);
214
159
  };
215
- const { treeViewItems, nodeIndex } = buildTreeViewItems(networks, temporaryNetworks);
216
- const temporaryNetworkExpirationTimes = temporaryNetworks.reduce((acc, tempNetwork) => {
217
- acc[tempNetwork.agentInfo.agent_name] = new Date(tempNetwork.reservation.expiration_time_in_seconds * 1000);
218
- return acc;
219
- }, {});
220
- const temporaryNetworkHoconStrings = temporaryNetworks.reduce((acc, tempNetwork) => {
221
- acc[tempNetwork.agentInfo.agent_name] = tempNetwork.networkHocon;
222
- return acc;
223
- }, {});
160
+ const treeViewItems = buildTreeViewItems(useNativeNames, networks, temporaryNetworks, networkIconSuggestions);
224
161
  const handleSelectedItemsChange = (_event, itemId) => {
225
162
  if (!itemId) {
226
163
  return;
227
164
  }
228
- // Only select leaf nodes (items in nodeIndex) as networks
229
- const isLeafNode = nodeIndex.has(itemId);
230
- if (!isLeafNode) {
165
+ const treeItem = findTreeItemById(treeViewItems, itemId);
166
+ if (!treeItem) {
167
+ return;
168
+ }
169
+ // Only allow selecting child nodes (i.e., actual networks), not parent nodes (folders).
170
+ if (!treeItem.isNetwork) {
231
171
  return;
232
172
  }
233
173
  // Don't allow selecting expired temporary networks
234
- const expirationTime = temporaryNetworkExpirationTimes[itemId];
174
+ const expirationTime = treeItem?.temporaryNetworkExpirationTime;
235
175
  if (expirationTime && expirationTime < new Date()) {
236
176
  return;
237
177
  }
@@ -251,7 +191,7 @@ export const Sidebar = ({ customURLCallback, customURLLocalStorage, id, isAwaiti
251
191
  in MUI RichTreeView including the imperative API (https://mui.com/x/react-tree-view/rich-tree-view/selection/#imperative-api)
252
192
  but couldn't get it to work so resorting to this for now.
253
193
  */
254
- const temporaryNetworkNode = document.querySelector(`[data-itemid="${firstItem}"]`);
194
+ const temporaryNetworkNode = document.querySelector(`[data-itemid="${CSS.escape(firstItem)}"]`);
255
195
  if (temporaryNetworkNode) {
256
196
  temporaryNetworkNode.scrollIntoView({ behavior: "smooth", block: "nearest", inline: "nearest" });
257
197
  temporaryNetworkNode.classList.add(SPARKLE_HIGHLIGHT_CLASS);
@@ -266,53 +206,29 @@ export const Sidebar = ({ customURLCallback, customURLLocalStorage, id, isAwaiti
266
206
  clearTimeout(removeHighlightTimeout);
267
207
  };
268
208
  }, [newlyAddedTemporaryNetworks]);
269
- return (_jsxs(_Fragment, { children: [_jsxs(SidebarAside, { id: `${id}-sidebar`, children: [_jsxs(SidebarHeading, { id: `${id}-heading`, children: ["Agent Networks", _jsxs(Box, { sx: { display: "flex" }, children: [_jsx(Button, { "aria-label": "Add New Network", disabled: isAwaitingLlm, id: "add-network-btn", onClick: () => {
270
- setSelectedItem(AGENT_NETWORK_DESIGNER_ID);
271
- setSelectedNetwork(AGENT_NETWORK_DESIGNER_ID);
272
- }, sx: { display: "inline-block", minWidth: "40px" }, children: _jsx(Tooltip, { title: "Create your own agent network", placement: "top", children: _jsx(AddBoxRounded, { id: "add-network-icon", sx: { color: isAwaitingLlm ? "rgba(0, 0, 0, 0.12)" : "var(--bs-secondary)" } }) }) }), _jsx(Button, { "aria-label": "Agent Network Settings", disabled: isAwaitingLlm, id: "agent-network-settings-btn", onClick: handleSettingsClick, sx: { display: "inline-block", minWidth: "40px" }, children: _jsx(Tooltip, { id: "agent-network-settings-tooltip", placement: "top", title: `${customURLLocalStorage || backendNeuroSanApiUrl}\nversion: ${testConnectionResult?.version || "unknown"}`, children: _jsx(SettingsIcon, { id: "agent-network-settings-icon", sx: {
273
- color: isAwaitingLlm ? "rgba(0, 0, 0, 0.12)" : "var(--bs-secondary)",
274
- } }) }) })] })] }), _jsx(RichTreeView, { items: treeViewItems, expandedItems: expandedItems, onExpandedItemsChange: (_event, itemIds) => setExpandedItems(itemIds), multiSelect: false, onSelectedItemsChange: handleSelectedItemsChange, selectedItems: selectedItem, disableSelection: isAwaitingLlm, slots: {
275
- item: AgentNetworkTreeItem,
276
- },
277
- // Pass custom props to tree items via slotProps.
278
- // Reference: https://github.com/mui/mui-x/issues/13351
279
- slotProps: {
280
- item: {
281
- networkIconSuggestions,
282
- nodeIndex,
283
- onDeleteNetwork,
284
- onEditNetwork: handleEditNetworkWithSelect,
285
- temporaryNetworkExpirationTimes,
286
- temporaryNetworkHoconStrings,
287
- },
288
- } }, Object.keys(networkIconSuggestions || {}).length)] }), _jsxs(Popover, { id: "agent-network-settings-popover", open: settingsPopoverOpen, anchorEl: settingsAnchorEl, onClose: () => handleSettingsClose(true), anchorOrigin: {
289
- vertical: "bottom",
290
- horizontal: "left",
291
- }, slotProps: {
292
- paper: {
293
- sx: {
294
- paddingTop: "0.75rem",
295
- paddingLeft: "0.5rem",
296
- paddingRight: "0.5rem",
297
- paddingBottom: "0.2rem",
298
- },
299
- },
300
- }, children: [_jsx(TextField, { autoComplete: "off", label: "Agent server address", id: "agent-network-settings-url", onChange: handleURLChange, onKeyUp: handleSettingsSaveEnterKey, placeholder: "https://my_server_address:port", size: "small", sx: { marginBottom: "0.5rem", minWidth: "400px" }, type: "url", variant: "outlined", value: urlInput, slotProps: {
301
- input: {
302
- endAdornment: urlInput && urlInput !== backendNeuroSanApiUrl ? (_jsx(InputAdornment, { id: "clear-input-adornment", position: "end", children: _jsx(IconButton, { id: "clear-input-icon-button", edge: "end", onClick: handleClearInput, size: "small", "aria-label": "Clear input", children: _jsx(ClearIcon, { fontSize: "small", id: "clear-input-icon" }) }) })) : undefined,
303
- },
304
- } }), _jsx(PrimaryButton, { disabled: !urlInput, id: "agent-network-settings-test-btn", onClick: handleTestConnection, variant: "contained", children: "Test" }), _jsx(PrimaryButton, { disabled: !saveEnabled, id: "agent-network-settings-save-btn", onClick: handleSaveSettings, variant: "contained", children: "Save" }), _jsx(PrimaryButton, { id: "agent-network-settings-cancel-btn", onClick: () => handleSettingsClose(true), variant: "contained", children: "Cancel" }), _jsx(Button, { id: "agent-network-settings-default-btn", onClick: handleDefaultSettings, sx: {
305
- marginLeft: "0.35rem",
306
- marginTop: "2px",
307
- color: darkMode ? "var(--bs-dark-mode-link)" : undefined,
308
- }, variant: "text", children: "Default" }), (connectionStatusSuccess || connectionStatusError) && (_jsxs(Box, { id: "connection-status-box", sx: {
309
- display: "flex",
310
- alignItems: "center",
311
- marginLeft: "0.25rem",
312
- marginBottom: "0.5rem",
313
- }, children: [connectionStatusSuccess && (_jsxs(_Fragment, { children: [_jsx(CheckCircleOutlinedIcon, { id: "connection-status-success-icon", sx: { color: "var(--bs-green)", fontSize: "1.2rem", marginRight: "0.25rem" } }), _jsx(Typography, { id: "connection-status-success-msg", variant: "body2", sx: {
314
- color: "var(--bs-green)",
315
- }, children: "Connected successfully" })] })), connectionStatusError && (_jsxs(_Fragment, { children: [_jsx(HighlightOff, { id: "connection-status-error-icon", sx: { color: "var(--bs-red)", fontSize: "1.2rem", marginRight: "0.25rem" } }), _jsx(Typography, { id: "connection-status-failed-msg", variant: "body2", sx: {
316
- color: "var(--bs-red)",
317
- }, children: `Connection failed: "${testConnectionResult?.status || "unknown error"}"` })] }))] }))] })] }));
209
+ const toStatusColor = () => {
210
+ switch (neuroSanServerStatus.onlineStatus) {
211
+ case "online":
212
+ return "green";
213
+ case "offline":
214
+ return "red";
215
+ case "unknown":
216
+ default:
217
+ return "unknown";
218
+ }
219
+ };
220
+ const getStatusLight = () => (_jsx(ServerStatusTooltip, { slotProps: {
221
+ popper: {
222
+ "aria-label": "Neuro-san server status",
223
+ },
224
+ }, title: _jsxs(Box, { sx: { display: "flex", flexDirection: "column", gap: 0.5 }, children: [_jsxs(Typography, { variant: "body2", children: [_jsx("strong", { children: "Status:" }), " ", neuroSanServerStatus.onlineStatus] }), _jsxs(Typography, { variant: "body2", children: [_jsx("strong", { children: "Version:" }), " ", neuroSanServerStatus.version ?? "unknown"] }), _jsxs(Typography, { variant: "body2", children: [_jsx("strong", { children: "URL:" }), " ", neuroSanServerURL || "unknown"] }), neuroSanServerStatus.error && (_jsxs(_Fragment, { children: [_jsxs(Typography, { variant: "body2", children: [_jsx("strong", { children: "Error:" }), " ", neuroSanServerStatus.error] }), neuroSanServerStatus.httpStatus && (_jsxs(Typography, { variant: "body2", children: [_jsx("strong", { children: "HTTP status:" }), " ", `${neuroSanServerStatus.httpStatus} (${httpStatus[neuroSanServerStatus.httpStatus] ?? "Unknown status"})`] }))] }))] }), placement: "right", children: _jsx("span", { children: _jsx(StatusLight, { id: `${id}-agent-network-status-light`, statusValue: toStatusColor() }) }) }));
225
+ const getAddNetworkButton = () => (_jsx(Box, { sx: { display: "flex" }, children: _jsx(Button, { "aria-label": "Add New Network", disabled: isAwaitingLlm, id: "add-network-btn", onClick: () => {
226
+ setSelectedItem(AGENT_NETWORK_DESIGNER_ID);
227
+ setSelectedNetwork(AGENT_NETWORK_DESIGNER_ID);
228
+ }, sx: { display: "inline-block", minWidth: "40px" }, children: _jsx(Tooltip, { title: "Create your own agent network", placement: "top", children: _jsx(AddBoxRounded, { id: "add-network-icon", sx: { color: "var(--bs-secondary)" } }) }) }) }));
229
+ const getSidebarHeading = () => (_jsxs(SidebarHeading, { id: `${id}-heading`, children: [_jsxs(Box, { sx: { display: "flex", alignItems: "center", gap: (theme) => theme.spacing(1.5) }, children: [getStatusLight(), "Agent Networks"] }), getAddNetworkButton()] }));
230
+ const getSidebarNetworksTree = () => (_jsx(RichTreeView, { disableSelection: isAwaitingLlm, expandedItems: expandedItems, items: treeViewItems, multiSelect: false, onExpandedItemsChange: (_event, itemIds) => setExpandedItems(itemIds), onSelectedItemsChange: handleSelectedItemsChange, selectedItems: selectedItem, slotProps: {
231
+ item: { onDeleteNetwork, onEditNetwork: handleEditNetworkWithSelect },
232
+ }, slots: { item: AgentNetworkTreeItem } }));
233
+ return (_jsxs(SidebarAside, { id: `${id}-sidebar`, children: [getSidebarHeading(), getSidebarNetworksTree()] }));
318
234
  };
@@ -1,20 +1,37 @@
1
1
  import { TreeViewDefaultItemModelProperties } from "@mui/x-tree-view/models";
2
2
  import { AgentInfo } from "../../../generated/neuro-san/NeuroSanClient.js";
3
3
  import { TemporaryNetwork } from "../../../state/TemporaryNetworks.js";
4
- export type NodeIndex = Map<string, {
5
- agentInfo: AgentInfo;
6
- displayName: string;
7
- }>;
4
+ /**
5
+ * Represents either a category (folder) or a network (leaf) in the tree view.
6
+ * Note that we omit the `children` property from the parent as we want to use read-only semantics
7
+ */
8
+ export interface AgentNetworkTreeItemModel extends Omit<TreeViewDefaultItemModelProperties, "children"> {
9
+ readonly children?: readonly AgentNetworkTreeItemModel[];
10
+ readonly displayName: string;
11
+ readonly iconSuggestion?: string;
12
+ readonly isNetwork: boolean;
13
+ readonly tags?: readonly string[];
14
+ readonly temporaryNetworkExpirationTime?: Date;
15
+ readonly temporaryNetworkHocon?: string | null;
16
+ }
17
+ /**
18
+ * Recursively searches for a tree item with the specified ID within the given list of tree items.
19
+ * @param items - The list of tree items to search through
20
+ * @param itemId - The ID of the tree item to find
21
+ * @returns The tree item with the matching ID, or undefined if not found
22
+ *
23
+ * @note Short-circuiting is used to avoid unnecessary searches once a match is found (compared to e.g., `flatMap()`)
24
+ */
25
+ export declare const findTreeItemById: (items: readonly AgentNetworkTreeItemModel[], itemId: string) => AgentNetworkTreeItemModel | undefined;
8
26
  /**
9
27
  * Build a tree view structure from a flat list of networks.
10
28
  * The list of networks comes from a call to the Neuro-san /list API
11
- * The tree structure is used by the RichTreeView component to display the networks
12
- * @param networks - Array of networks from the Neuro-san /list API
13
- * @param temporaryNetworks - Array of temporary networks (e.g. ones recently created by the user)
14
- * @returns Array of {@linkcode TreeViewDefaultItemModelProperties} objects representing the tree structure and an
15
- * index for rapid access
29
+ * The tree structure is used by the RichTreeView component to display the networks.
30
+ *
31
+ * @param useNativeNames - Whether to use the raw agent names from the API or to clean them up for display.
32
+ * @param regularNetworks - Array of networks from the Neuro-san /list API
33
+ * @param temporaryNetworks - Array of temporary networks (e.g., ones recently created by the user)
34
+ * @param iconSuggestions
35
+ * @returns Array of {@linkcode AgentNetworkTreeItemModel} objects representing the tree structure
16
36
  */
17
- export declare const buildTreeViewItems: (networks: readonly AgentInfo[], temporaryNetworks: readonly TemporaryNetwork[]) => {
18
- treeViewItems: TreeViewDefaultItemModelProperties[];
19
- nodeIndex: NodeIndex;
20
- };
37
+ export declare const buildTreeViewItems: (useNativeNames: boolean, regularNetworks?: readonly AgentInfo[], temporaryNetworks?: readonly TemporaryNetwork[], iconSuggestions?: Record<string, string>) => AgentNetworkTreeItemModel[];