@cognizant-ai-lab/ui-common 1.3.3 → 1.4.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.
- package/README.md +287 -0
- package/dist/Theme/Palettes.d.ts +18 -0
- package/dist/Theme/Palettes.js +94 -0
- package/dist/Theme/Theme.d.ts +22 -0
- package/dist/Theme/Theme.js +58 -0
- package/dist/components/AgentChat/ChatCommon.d.ts +4 -2
- package/dist/components/AgentChat/ChatCommon.js +141 -105
- package/dist/components/AgentChat/ControlButtons.js +3 -1
- package/dist/components/AgentChat/FormattedMarkdown.d.ts +4 -4
- package/dist/components/AgentChat/FormattedMarkdown.js +5 -7
- package/dist/components/AgentChat/LlmChatButton.d.ts +2 -6
- package/dist/components/AgentChat/LlmChatButton.js +3 -3
- package/dist/components/AgentChat/UserQueryDisplay.js +2 -4
- package/dist/components/AgentChat/Utils.d.ts +2 -1
- package/dist/components/AgentChat/Utils.js +4 -1
- package/dist/components/AgentChat/VoiceChat/MicrophoneButton.d.ts +2 -2
- package/dist/components/AgentChat/VoiceChat/VoiceChat.d.ts +3 -3
- package/dist/components/AgentChat/VoiceChat/VoiceChat.js +5 -5
- package/dist/components/ChatBot/ChatBot.js +2 -2
- package/dist/components/Common/Breadcrumbs.js +1 -1
- package/dist/components/Common/{confirmationModal.js → ConfirmationModal.js} +2 -5
- package/dist/components/Common/CustomerLogo.d.ts +17 -0
- package/dist/components/Common/CustomerLogo.js +49 -0
- package/dist/components/Common/Footer.d.ts +18 -0
- package/dist/components/Common/Footer.js +59 -0
- package/dist/components/Common/LlmChatOptionsButton.d.ts +1 -4
- package/dist/components/Common/LlmChatOptionsButton.js +4 -4
- package/dist/components/Common/LoadingSpinner.js +1 -1
- package/dist/components/Common/MUIAccordion.d.ts +2 -2
- package/dist/components/Common/MUIAccordion.js +2 -12
- package/dist/components/Common/MUIAlert.d.ts +2 -1
- package/dist/components/Common/MUIAlert.js +4 -1
- package/dist/components/Common/MUIDialog.d.ts +1 -1
- package/dist/components/Common/MUIDialog.js +1 -1
- package/dist/components/Common/Navbar.d.ts +3 -1
- package/dist/components/Common/Navbar.js +60 -35
- package/dist/components/Common/PageLoader.js +3 -4
- package/dist/components/Common/Snackbar.d.ts +4 -1
- package/dist/components/Common/Snackbar.js +11 -19
- package/dist/components/Common/notification.d.ts +3 -3
- package/dist/components/Common/notification.js +6 -6
- package/dist/components/ErrorPage/ErrorBoundary.d.ts +2 -2
- package/dist/components/ErrorPage/ErrorBoundary.js +1 -1
- package/dist/components/ErrorPage/ErrorPage.js +6 -5
- package/dist/components/MultiAgentAccelerator/AgentConversations.d.ts +17 -0
- package/dist/components/MultiAgentAccelerator/AgentConversations.js +77 -0
- package/dist/components/MultiAgentAccelerator/AgentCounts.d.ts +12 -0
- package/dist/components/MultiAgentAccelerator/AgentCounts.js +21 -0
- package/dist/components/MultiAgentAccelerator/AgentFlow.d.ts +6 -4
- package/dist/components/MultiAgentAccelerator/AgentFlow.js +106 -185
- package/dist/components/MultiAgentAccelerator/AgentNode.d.ts +7 -5
- package/dist/components/MultiAgentAccelerator/AgentNode.js +93 -50
- package/dist/components/MultiAgentAccelerator/GraphLayouts.d.ts +20 -17
- package/dist/components/MultiAgentAccelerator/GraphLayouts.js +16 -14
- package/dist/components/MultiAgentAccelerator/MultiAgentAccelerator.d.ts +2 -3
- package/dist/components/MultiAgentAccelerator/MultiAgentAccelerator.js +214 -55
- package/dist/components/MultiAgentAccelerator/PlasmaEdge.d.ts +1 -1
- package/dist/components/MultiAgentAccelerator/PlasmaEdge.js +14 -12
- package/dist/components/MultiAgentAccelerator/Sidebar/AgentNetworkTreeItem.d.ts +15 -0
- package/dist/components/MultiAgentAccelerator/Sidebar/AgentNetworkTreeItem.js +104 -0
- package/dist/components/MultiAgentAccelerator/Sidebar/Sidebar.d.ts +17 -0
- package/dist/components/MultiAgentAccelerator/{Sidebar.js → Sidebar/Sidebar.js} +146 -59
- package/dist/components/MultiAgentAccelerator/Sidebar/TreeBuilder.d.ts +19 -0
- package/dist/components/MultiAgentAccelerator/Sidebar/TreeBuilder.js +113 -0
- package/dist/components/MultiAgentAccelerator/TemporaryNetworks.d.ts +26 -0
- package/dist/components/MultiAgentAccelerator/TemporaryNetworks.js +20 -0
- package/dist/components/MultiAgentAccelerator/ThoughtBubbleEdge.d.ts +10 -8
- package/dist/components/MultiAgentAccelerator/ThoughtBubbleEdge.js +1 -1
- package/dist/components/MultiAgentAccelerator/ThoughtBubbleOverlay.d.ts +3 -2
- package/dist/components/MultiAgentAccelerator/ThoughtBubbleOverlay.js +10 -13
- package/dist/components/MultiAgentAccelerator/const.d.ts +1 -3
- package/dist/components/MultiAgentAccelerator/const.js +4 -18
- package/dist/components/Settings/FadingCheckmark.d.ts +14 -0
- package/dist/components/Settings/FadingCheckmark.js +43 -0
- package/dist/components/Settings/SettingsDialog.d.ts +9 -0
- package/dist/components/Settings/SettingsDialog.js +265 -0
- package/dist/const.d.ts +1 -2
- package/dist/const.js +2 -3
- package/dist/controller/Types/AgentIconSuggestions.d.ts +4 -0
- package/dist/controller/Types/AgentIconSuggestions.js +1 -0
- package/dist/controller/Types/Branding.d.ts +12 -0
- package/dist/controller/Types/Branding.js +1 -0
- package/dist/controller/Types/NetworkIconSuggestions.d.ts +4 -0
- package/dist/controller/Types/NetworkIconSuggestions.js +1 -0
- package/dist/controller/agent/Agent.d.ts +32 -12
- package/dist/controller/agent/Agent.js +71 -19
- package/dist/controller/llm/LlmChat.d.ts +1 -1
- package/dist/controller/llm/LlmChat.js +2 -2
- package/dist/index.d.ts +10 -5
- package/dist/index.js +10 -5
- package/dist/state/{environment.d.ts → Environment.d.ts} +2 -0
- package/dist/state/{environment.js → Environment.js} +2 -0
- package/dist/state/Settings.d.ts +62 -0
- package/dist/state/Settings.js +62 -0
- package/dist/state/TemporaryNetworks.d.ts +32 -0
- package/dist/state/TemporaryNetworks.js +26 -0
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/dist/utils/Authentication.d.ts +2 -2
- package/dist/utils/Authentication.js +6 -6
- package/dist/utils/text.d.ts +2 -2
- package/dist/utils/text.js +3 -5
- package/dist/utils/title.d.ts +1 -1
- package/dist/utils/title.js +2 -2
- package/dist/utils/useLocalStorage.d.ts +1 -1
- package/dist/utils/useLocalStorage.js +3 -3
- package/dist/utils/zIndexLayers.d.ts +1 -1
- package/dist/utils/zIndexLayers.js +3 -15
- package/package.json +23 -21
- package/dist/components/MultiAgentAccelerator/Sidebar.d.ts +0 -12
- package/dist/utils/Theme.d.ts +0 -7
- package/dist/utils/Theme.js +0 -7
- package/dist/utils/agentConversations.d.ts +0 -24
- package/dist/utils/agentConversations.js +0 -113
- /package/dist/components/Common/{confirmationModal.d.ts → ConfirmationModal.d.ts} +0 -0
|
@@ -18,36 +18,92 @@ import CheckCircleOutlineIcon from "@mui/icons-material/CheckCircleOutline";
|
|
|
18
18
|
import ClearIcon from "@mui/icons-material/Clear";
|
|
19
19
|
import HighlightOff from "@mui/icons-material/HighlightOff";
|
|
20
20
|
import SettingsIcon from "@mui/icons-material/Settings";
|
|
21
|
-
import { IconButton, InputAdornment, styled, useColorScheme, useTheme } from "@mui/material";
|
|
22
21
|
import Box from "@mui/material/Box";
|
|
23
22
|
import Button from "@mui/material/Button";
|
|
24
|
-
import
|
|
25
|
-
import
|
|
26
|
-
import ListItemText from "@mui/material/ListItemText";
|
|
23
|
+
import IconButton from "@mui/material/IconButton";
|
|
24
|
+
import InputAdornment from "@mui/material/InputAdornment";
|
|
27
25
|
import Popover from "@mui/material/Popover";
|
|
26
|
+
import { keyframes, styled, useTheme } from "@mui/material/styles";
|
|
28
27
|
import TextField from "@mui/material/TextField";
|
|
29
28
|
import Tooltip from "@mui/material/Tooltip";
|
|
30
29
|
import Typography from "@mui/material/Typography";
|
|
31
|
-
import {
|
|
32
|
-
import {
|
|
33
|
-
import {
|
|
34
|
-
import {
|
|
35
|
-
import {
|
|
36
|
-
import {
|
|
30
|
+
import { RichTreeView } from "@mui/x-tree-view/RichTreeView";
|
|
31
|
+
import { useEffect, useState, } from "react";
|
|
32
|
+
import { AgentNetworkTreeItem } from "./AgentNetworkTreeItem.js";
|
|
33
|
+
import { buildTreeViewItems } from "./TreeBuilder.js";
|
|
34
|
+
import { testConnection } from "../../../controller/agent/Agent.js";
|
|
35
|
+
import { useEnvironmentStore } from "../../../state/Environment.js";
|
|
36
|
+
import { getZIndex } from "../../../utils/zIndexLayers.js";
|
|
37
|
+
import { TEMPORARY_NETWORK_FOLDER } from "../const.js";
|
|
38
|
+
// Animation for the sparkle effect when a new temporary network is added.
|
|
39
|
+
const sparkle = keyframes `
|
|
40
|
+
0% {
|
|
41
|
+
background-position: 0% 50%;
|
|
42
|
+
opacity: 1;
|
|
43
|
+
}
|
|
44
|
+
10% {
|
|
45
|
+
background-position: 33% 50%;
|
|
46
|
+
opacity: 1;
|
|
47
|
+
}
|
|
48
|
+
20% {
|
|
49
|
+
background-position: 66% 50%;
|
|
50
|
+
opacity: 1;
|
|
51
|
+
}
|
|
52
|
+
30% {
|
|
53
|
+
background-position: 100% 50%;
|
|
54
|
+
opacity: 1;
|
|
55
|
+
}
|
|
56
|
+
60% {
|
|
57
|
+
background-position: 100% 50%;
|
|
58
|
+
opacity: 1;
|
|
59
|
+
}
|
|
60
|
+
80% {
|
|
61
|
+
background-position: 100% 50%;
|
|
62
|
+
opacity: 0.7;
|
|
63
|
+
}
|
|
64
|
+
90% {
|
|
65
|
+
background-position: 100% 50%;
|
|
66
|
+
opacity: 0.4;
|
|
67
|
+
}
|
|
68
|
+
100% {
|
|
69
|
+
background-position: 100% 50%;
|
|
70
|
+
opacity: 0.25;
|
|
71
|
+
}
|
|
72
|
+
`;
|
|
37
73
|
// #region: Styled Components
|
|
38
|
-
const PrimaryButton = styled(Button
|
|
39
|
-
shouldForwardProp: (prop) => prop !== "darkMode",
|
|
40
|
-
})(({ darkMode }) => ({
|
|
41
|
-
backgroundColor: "var(--bs-primary)",
|
|
74
|
+
const PrimaryButton = styled(Button)({
|
|
42
75
|
marginLeft: "0.5rem",
|
|
43
76
|
marginTop: "2px",
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
77
|
+
});
|
|
78
|
+
// Styled component for Sidebar aside element, including styles for the sparkle highlight animation
|
|
79
|
+
// when a new temporary network is added.
|
|
80
|
+
const SidebarAside = styled("aside")({
|
|
81
|
+
borderRightStyle: "solid",
|
|
82
|
+
borderRightWidth: "1px",
|
|
83
|
+
height: "100%",
|
|
84
|
+
overflowY: "auto",
|
|
85
|
+
paddingRight: "0.75rem",
|
|
86
|
+
"& .sparkle-highlight": {
|
|
87
|
+
background: "linear-gradient(90deg, gold, orange, cyan, magenta, gold)",
|
|
88
|
+
backgroundSize: "400% 100%",
|
|
89
|
+
animation: `${sparkle} 5s ease`,
|
|
90
|
+
backgroundClip: "padding-box",
|
|
91
|
+
borderRadius: "4px",
|
|
92
|
+
opacity: 1,
|
|
50
93
|
},
|
|
94
|
+
});
|
|
95
|
+
// Styled component for the sidebar heading, which is sticky at the top of the sidebar.
|
|
96
|
+
const SidebarHeading = styled("h2")(({ theme }) => ({
|
|
97
|
+
backgroundColor: theme.palette.background.default,
|
|
98
|
+
borderBottomStyle: "solid",
|
|
99
|
+
borderBottomWidth: "1px",
|
|
100
|
+
fontSize: "1.125rem",
|
|
101
|
+
fontWeight: "bold",
|
|
102
|
+
marginBottom: "0.25rem",
|
|
103
|
+
paddingBottom: "0.75rem",
|
|
104
|
+
position: "sticky",
|
|
105
|
+
top: 0,
|
|
106
|
+
zIndex: getZIndex(1, theme),
|
|
51
107
|
}));
|
|
52
108
|
// #endregion: Styled Components
|
|
53
109
|
// #region: Types
|
|
@@ -58,7 +114,8 @@ var CONNECTION_STATUS;
|
|
|
58
114
|
CONNECTION_STATUS["ERROR"] = "error";
|
|
59
115
|
})(CONNECTION_STATUS || (CONNECTION_STATUS = {}));
|
|
60
116
|
// #endregion: Types
|
|
61
|
-
|
|
117
|
+
const EMPTY_ARRAY = [];
|
|
118
|
+
export const Sidebar = ({ customURLCallback, customURLLocalStorage, id, isAwaitingLlm, networkIconSuggestions, networks, newlyAddedTemporaryNetworks, onDeleteNetwork, setSelectedNetwork, temporaryNetworks = EMPTY_ARRAY, }) => {
|
|
62
119
|
// Get default URL from the environment store.
|
|
63
120
|
const { backendNeuroSanApiUrl } = useEnvironmentStore();
|
|
64
121
|
const [urlInput, setUrlInput] = useState(customURLLocalStorage || backendNeuroSanApiUrl);
|
|
@@ -67,16 +124,13 @@ export const Sidebar = ({ customURLCallback, customURLLocalStorage, id, isAwaiti
|
|
|
67
124
|
const connectionStatusSuccess = connectionStatus === CONNECTION_STATUS.SUCCESS;
|
|
68
125
|
const connectionStatusError = connectionStatus === CONNECTION_STATUS.ERROR;
|
|
69
126
|
const isDefaultUrl = urlInput === backendNeuroSanApiUrl;
|
|
70
|
-
// Enable the Save button if the URL input is not empty and the connection status is successful,
|
|
71
|
-
// OR if the URL input is the default URL and connection status is not error
|
|
72
127
|
const saveEnabled = urlInput && (connectionStatusSuccess || (isDefaultUrl && !connectionStatusError));
|
|
73
|
-
const selectedNetworkRef = useRef(null);
|
|
74
128
|
const [settingsAnchorEl, setSettingsAnchorEl] = useState(null);
|
|
75
129
|
const settingsPopoverOpen = Boolean(settingsAnchorEl);
|
|
130
|
+
const [expandedItems, setExpandedItems] = useState([]);
|
|
76
131
|
// Theming/Dark mode
|
|
77
132
|
const theme = useTheme();
|
|
78
|
-
const
|
|
79
|
-
const darkMode = isDarkMode(mode, systemMode);
|
|
133
|
+
const darkMode = theme.palette.mode === "dark";
|
|
80
134
|
const handleSettingsClick = (event) => {
|
|
81
135
|
// On open of Settings popover, reset the connection status to idle
|
|
82
136
|
setConnectionStatus(CONNECTION_STATUS.IDLE);
|
|
@@ -132,12 +186,6 @@ export const Sidebar = ({ customURLCallback, customURLLocalStorage, id, isAwaiti
|
|
|
132
186
|
setUrlInput("");
|
|
133
187
|
setConnectionStatus(CONNECTION_STATUS.IDLE);
|
|
134
188
|
};
|
|
135
|
-
// Make sure selected network in the list is always in view
|
|
136
|
-
useEffect(() => {
|
|
137
|
-
if (selectedNetworkRef.current) {
|
|
138
|
-
selectedNetworkRef.current.scrollIntoView({ behavior: "instant", block: "nearest" });
|
|
139
|
-
}
|
|
140
|
-
}, [selectedNetwork]);
|
|
141
189
|
// Get Neuro-san version on initial load
|
|
142
190
|
useEffect(() => {
|
|
143
191
|
const fetchVersion = async () => {
|
|
@@ -150,34 +198,73 @@ export const Sidebar = ({ customURLCallback, customURLLocalStorage, id, isAwaiti
|
|
|
150
198
|
};
|
|
151
199
|
void fetchVersion();
|
|
152
200
|
}, []);
|
|
153
|
-
const
|
|
154
|
-
|
|
201
|
+
const { treeViewItems, nodeIndex } = buildTreeViewItems(networks, temporaryNetworks);
|
|
202
|
+
const temporaryNetworkExpirationTimes = temporaryNetworks.reduce((acc, tempNetwork) => {
|
|
203
|
+
acc[tempNetwork.agentInfo.agent_name] = new Date(tempNetwork.reservation.expiration_time_in_seconds * 1000);
|
|
204
|
+
return acc;
|
|
205
|
+
}, {});
|
|
206
|
+
const [selectedItem, setSelectedItem] = useState(null);
|
|
207
|
+
const handleSelectedItemsChange = (_event, itemId) => {
|
|
208
|
+
if (!itemId) {
|
|
209
|
+
return;
|
|
210
|
+
}
|
|
211
|
+
// Only select leaf nodes (items in nodeIndex) as networks
|
|
212
|
+
const isLeafNode = nodeIndex.has(itemId);
|
|
213
|
+
if (!isLeafNode) {
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
// Don't allow selecting expired temporary networks
|
|
217
|
+
const expirationTime = temporaryNetworkExpirationTimes[itemId];
|
|
218
|
+
if (expirationTime && expirationTime < new Date()) {
|
|
219
|
+
return;
|
|
220
|
+
}
|
|
221
|
+
setSelectedItem(itemId);
|
|
222
|
+
setSelectedNetwork(itemId);
|
|
155
223
|
};
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
224
|
+
useEffect(() => {
|
|
225
|
+
let highlightTimeout;
|
|
226
|
+
let removeHighlightTimeout;
|
|
227
|
+
// If we got a new temporary network, select it and expand the temporary category in the tree view
|
|
228
|
+
if (newlyAddedTemporaryNetworks?.size > 0) {
|
|
229
|
+
const firstItem = newlyAddedTemporaryNetworks.values().next().value;
|
|
230
|
+
setSelectedItem(firstItem);
|
|
231
|
+
setSelectedNetwork(firstItem);
|
|
232
|
+
setExpandedItems((prev) => prev.includes(TEMPORARY_NETWORK_FOLDER) ? prev : [...prev, TEMPORARY_NETWORK_FOLDER]);
|
|
233
|
+
highlightTimeout = setTimeout(() => {
|
|
234
|
+
// Scroll the selected node into view and add an animation to draw the user's attention to it.
|
|
235
|
+
// Hacky: use a DOM query to find the node. I tried the various ways to do this programmatically
|
|
236
|
+
// in MUI RichTreeView including the imperative API (https://mui.com/x/react-tree-view/rich-tree-view/selection/#imperative-api)
|
|
237
|
+
// but couldn't get it to work so resorting to this for now.
|
|
238
|
+
const selectedNode = document.querySelector("[role=treeitem][aria-checked=true]");
|
|
239
|
+
if (selectedNode) {
|
|
240
|
+
selectedNode.scrollIntoView({ behavior: "smooth", block: "nearest", inline: "nearest" });
|
|
241
|
+
selectedNode.classList.add("sparkle-highlight");
|
|
242
|
+
removeHighlightTimeout = setTimeout(() => {
|
|
243
|
+
selectedNode.classList.remove("sparkle-highlight");
|
|
244
|
+
}, 5000);
|
|
245
|
+
}
|
|
246
|
+
}, 50);
|
|
247
|
+
}
|
|
248
|
+
return () => {
|
|
249
|
+
clearTimeout(highlightTimeout);
|
|
250
|
+
clearTimeout(removeHighlightTimeout);
|
|
251
|
+
};
|
|
252
|
+
}, [newlyAddedTemporaryNetworks]);
|
|
253
|
+
return (_jsxs(_Fragment, { children: [_jsxs(SidebarAside, { id: `${id}-sidebar`, children: [_jsxs(SidebarHeading, { id: `${id}-heading`, children: ["Agent Networks", _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: {
|
|
175
254
|
color: isAwaitingLlm ? "rgba(0, 0, 0, 0.12)" : "var(--bs-secondary)",
|
|
176
|
-
} }) }) })] }), _jsx(
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
255
|
+
} }) }) })] }), _jsx(RichTreeView, { items: treeViewItems, expandedItems: expandedItems, onExpandedItemsChange: (_event, itemIds) => setExpandedItems(itemIds), multiSelect: false, onSelectedItemsChange: handleSelectedItemsChange, selectedItems: selectedItem, disableSelection: isAwaitingLlm, slots: {
|
|
256
|
+
item: AgentNetworkTreeItem,
|
|
257
|
+
},
|
|
258
|
+
// Pass custom props to tree items via slotProps.
|
|
259
|
+
// Reference: https://github.com/mui/mui-x/issues/13351
|
|
260
|
+
slotProps: {
|
|
261
|
+
item: {
|
|
262
|
+
networkIconSuggestions,
|
|
263
|
+
nodeIndex,
|
|
264
|
+
onDeleteNetwork,
|
|
265
|
+
temporaryNetworkExpirationTimes,
|
|
266
|
+
},
|
|
267
|
+
} }, Object.keys(networkIconSuggestions || {}).length)] }), _jsxs(Popover, { id: "agent-network-settings-popover", open: settingsPopoverOpen, anchorEl: settingsAnchorEl, onClose: () => handleSettingsClose(true), anchorOrigin: {
|
|
181
268
|
vertical: "bottom",
|
|
182
269
|
horizontal: "left",
|
|
183
270
|
}, slotProps: {
|
|
@@ -193,7 +280,7 @@ export const Sidebar = ({ customURLCallback, customURLLocalStorage, id, isAwaiti
|
|
|
193
280
|
input: {
|
|
194
281
|
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,
|
|
195
282
|
},
|
|
196
|
-
} }), _jsx(PrimaryButton, { disabled: !urlInput, id: "agent-network-settings-test-btn", onClick: handleTestConnection, variant: "contained",
|
|
283
|
+
} }), _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: {
|
|
197
284
|
marginLeft: "0.35rem",
|
|
198
285
|
marginTop: "2px",
|
|
199
286
|
color: darkMode ? "var(--bs-dark-mode-link)" : undefined,
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { TreeViewBaseItem } from "@mui/x-tree-view/models";
|
|
2
|
+
import { AgentInfo } from "../../../generated/neuro-san/NeuroSanClient.js";
|
|
3
|
+
import { TemporaryNetwork } from "../../../state/TemporaryNetworks.js";
|
|
4
|
+
export type NodeIndex = Map<string, {
|
|
5
|
+
agentInfo: AgentInfo;
|
|
6
|
+
displayName: string;
|
|
7
|
+
}>;
|
|
8
|
+
/**
|
|
9
|
+
* Build a tree view structure from a flat list of networks.
|
|
10
|
+
* 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 TreeViewBaseItem objects representing the tree structure and an index for rapid access
|
|
15
|
+
*/
|
|
16
|
+
export declare const buildTreeViewItems: (networks: readonly AgentInfo[], temporaryNetworks: readonly TemporaryNetwork[]) => {
|
|
17
|
+
treeViewItems: TreeViewBaseItem[];
|
|
18
|
+
nodeIndex: NodeIndex;
|
|
19
|
+
};
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { cleanUpAgentName, removeTrailingUuid } from "../../AgentChat/Utils.js";
|
|
2
|
+
/**
|
|
3
|
+
* Iteratively sort all children of tree nodes using a queue-based approach
|
|
4
|
+
* @param nodes - Array of tree nodes to sort
|
|
5
|
+
*/
|
|
6
|
+
const sortTreeNodes = (nodes, nodeIndex) => {
|
|
7
|
+
// Sort the top level nodes first. We sort by displayName because that's what the user sees
|
|
8
|
+
nodes.sort((a, b) => {
|
|
9
|
+
const aDisplayName = nodeIndex.get(a.id)?.displayName ?? a.label;
|
|
10
|
+
const bDisplayName = nodeIndex.get(b.id)?.displayName ?? b.label;
|
|
11
|
+
return aDisplayName.localeCompare(bDisplayName);
|
|
12
|
+
});
|
|
13
|
+
// Use a queue for breadth-first traversal to avoid recursion
|
|
14
|
+
const queue = [...nodes];
|
|
15
|
+
let index = 0;
|
|
16
|
+
// For each node in the queue, sort its children and add them to the end of the queue
|
|
17
|
+
while (index < queue.length) {
|
|
18
|
+
const node = queue[index];
|
|
19
|
+
index += 1;
|
|
20
|
+
if (node.children && node.children.length > 0) {
|
|
21
|
+
node.children.sort((a, b) => {
|
|
22
|
+
const aDisplayName = nodeIndex.get(a.id)?.displayName ?? a.label;
|
|
23
|
+
const bDisplayName = nodeIndex.get(b.id)?.displayName ?? b.label;
|
|
24
|
+
return aDisplayName.localeCompare(bDisplayName);
|
|
25
|
+
});
|
|
26
|
+
queue.push(...node.children);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
/**
|
|
31
|
+
* Add a single AgentInfo entry into the tree structure
|
|
32
|
+
*/
|
|
33
|
+
const addNetworkToTree = (network, result, uncategorized, map, nodeIndex, displayNameCounts) => {
|
|
34
|
+
const parts = network.agent_name.split("/");
|
|
35
|
+
// If there's only one part, it means this network isn't in any folder, so we add it directly under "Uncategorized"
|
|
36
|
+
if (parts.length === 1) {
|
|
37
|
+
uncategorized.children.push({ id: network.agent_name, label: network.agent_name, children: [] });
|
|
38
|
+
nodeIndex.set(network.agent_name, { agentInfo: network, displayName: cleanUpAgentName(network.agent_name) });
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
// Otherwise, we need to build out the tree structure based on the parts of the agent_name. Some paths might
|
|
42
|
+
// already exist if we've processed another network that shares the same parent folders,
|
|
43
|
+
// so we check the map to avoid duplicating nodes.
|
|
44
|
+
let currentLevel = result;
|
|
45
|
+
parts.forEach((part, index) => {
|
|
46
|
+
// Build the full path ID by joining all parts up to the current position
|
|
47
|
+
const nodeId = parts.slice(0, index + 1).join("/");
|
|
48
|
+
let node = map.get(nodeId);
|
|
49
|
+
if (!node) {
|
|
50
|
+
// If we haven't created a node for this path yet, create it and add it to the map
|
|
51
|
+
node = { id: nodeId, label: part, children: [] };
|
|
52
|
+
map.set(nodeId, node);
|
|
53
|
+
if (index === parts.length - 1) {
|
|
54
|
+
const cleanedName = cleanUpAgentName(removeTrailingUuid(part));
|
|
55
|
+
// Handle duplicate display names by appending a number (e.g. "macys", "macys 2", "macys 3", etc.)
|
|
56
|
+
const count = displayNameCounts.get(cleanedName) || 0;
|
|
57
|
+
displayNameCounts.set(cleanedName, count + 1);
|
|
58
|
+
const displayName = count > 0 ? `${cleanedName} ${count + 1}` : cleanedName;
|
|
59
|
+
// Add the AgentInfo to the nodeIndex for quick lookup later, using the full path as the key
|
|
60
|
+
nodeIndex.set(nodeId, { agentInfo: network, displayName });
|
|
61
|
+
}
|
|
62
|
+
// If this is a top-level node (index 0), add it directly to the result.
|
|
63
|
+
// Otherwise, find its parent and add it there.
|
|
64
|
+
if (index === 0) {
|
|
65
|
+
// Top-level node, add directly to result
|
|
66
|
+
currentLevel.push(node);
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
// Not a top-level node, find parent and add to its children
|
|
70
|
+
const parentId = parts.slice(0, index).join("/");
|
|
71
|
+
const parentNode = map.get(parentId);
|
|
72
|
+
if (parentNode) {
|
|
73
|
+
parentNode.children.push(node);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
// Move down to the next level of the tree for the next iteration
|
|
78
|
+
currentLevel = node.children;
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
/**
|
|
83
|
+
* Build a tree view structure from a flat list of networks.
|
|
84
|
+
* The list of networks comes from a call to the Neuro-san /list API
|
|
85
|
+
* The tree structure is used by the RichTreeView component to display the networks
|
|
86
|
+
* @param networks - Array of networks from the Neuro-san /list API
|
|
87
|
+
* @param temporaryNetworks - Array of temporary networks (e.g. ones recently created by the user)
|
|
88
|
+
* @returns Array of TreeViewBaseItem objects representing the tree structure and an index for rapid access
|
|
89
|
+
*/
|
|
90
|
+
export const buildTreeViewItems = (networks, temporaryNetworks) => {
|
|
91
|
+
// Map to keep track of created nodes in a tree structure
|
|
92
|
+
const treeBuilderMap = new Map();
|
|
93
|
+
// Index to quickly look up AgentInfo by node ID without having to traverse the tree
|
|
94
|
+
const nodeIndex = new Map();
|
|
95
|
+
// Resulting tree view items, ready for consumption by RichTreeView
|
|
96
|
+
const treeViewItems = [];
|
|
97
|
+
// Special parent node for networks that aren't in any folder
|
|
98
|
+
const uncategorized = { id: "uncategorized", label: "Uncategorized", children: [] };
|
|
99
|
+
const displayNameCounts = new Map();
|
|
100
|
+
// Build a tree structure from the flat list of networks.
|
|
101
|
+
// The networks come in as a series of "paths" like "industry/retail/macys" and we need to build a tree
|
|
102
|
+
// structure from that.
|
|
103
|
+
networks.forEach((network) => addNetworkToTree(network, treeViewItems, uncategorized, treeBuilderMap, nodeIndex, displayNameCounts));
|
|
104
|
+
// Now handle temporary networks
|
|
105
|
+
temporaryNetworks?.forEach((temporaryNetwork) => addNetworkToTree(temporaryNetwork.agentInfo, treeViewItems, uncategorized, treeBuilderMap, nodeIndex, displayNameCounts));
|
|
106
|
+
// Add "Uncategorized" to the result if there are any such networks
|
|
107
|
+
if (uncategorized.children.length > 0) {
|
|
108
|
+
treeViewItems.push(uncategorized);
|
|
109
|
+
}
|
|
110
|
+
// Sort all nodes in the tree
|
|
111
|
+
sortTreeNodes(treeViewItems, nodeIndex);
|
|
112
|
+
return { treeViewItems, nodeIndex };
|
|
113
|
+
};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { ChatMessage } from "../../generated/neuro-san/NeuroSanClient.js";
|
|
2
|
+
/**
|
|
3
|
+
* Definition of a temporary network. No schema for this provided by backend so we second-guess it here.
|
|
4
|
+
* @see https://github.com/cognizant-ai-lab/neuro-san/issues/743
|
|
5
|
+
* @example
|
|
6
|
+
* ```json
|
|
7
|
+
* {
|
|
8
|
+
* "reservation_id": "copy_cat-hello_world-14ecb260-4389-44f3-afad-ea315dfa1966",
|
|
9
|
+
* "lifetime_in_seconds": 300.0,
|
|
10
|
+
* "expiration_time_in_seconds": 1771438301.0245166
|
|
11
|
+
* }
|
|
12
|
+
* ```
|
|
13
|
+
*/
|
|
14
|
+
export type AgentReservation = {
|
|
15
|
+
readonly reservation_id: string;
|
|
16
|
+
readonly lifetime_in_seconds: number;
|
|
17
|
+
readonly expiration_time_in_seconds: number;
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* Extracts agent reservations from a chat message, if they exist.
|
|
21
|
+
* @param message The chat message to extract reservations from. We expect reservations to be present in messages of
|
|
22
|
+
* type AGENT_FRAMEWORK only.
|
|
23
|
+
* @return An array of AgentReservation objects if reservations are found, or an empty array if not found or
|
|
24
|
+
* if the message is not of the expected type.
|
|
25
|
+
*/
|
|
26
|
+
export declare const extractReservations: (message: ChatMessage) => AgentReservation[];
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { ChatMessageType } from "../../generated/neuro-san/NeuroSanClient.js";
|
|
2
|
+
// We expect the agent reservations to be stored in sly_data under this key
|
|
3
|
+
const AGENT_RESERVATIONS_KEY = "agent_reservations";
|
|
4
|
+
/**
|
|
5
|
+
* Extracts agent reservations from a chat message, if they exist.
|
|
6
|
+
* @param message The chat message to extract reservations from. We expect reservations to be present in messages of
|
|
7
|
+
* type AGENT_FRAMEWORK only.
|
|
8
|
+
* @return An array of AgentReservation objects if reservations are found, or an empty array if not found or
|
|
9
|
+
* if the message is not of the expected type.
|
|
10
|
+
*/
|
|
11
|
+
export const extractReservations = (message) => {
|
|
12
|
+
// Check for temp networks ("reservations") in sly_data
|
|
13
|
+
if (message?.type === ChatMessageType.AGENT_FRAMEWORK && message?.sly_data?.[AGENT_RESERVATIONS_KEY]) {
|
|
14
|
+
return message.sly_data[AGENT_RESERVATIONS_KEY];
|
|
15
|
+
}
|
|
16
|
+
else {
|
|
17
|
+
// Not the type of message that would contain reservations, or no reservations found, return empty array
|
|
18
|
+
return [];
|
|
19
|
+
}
|
|
20
|
+
};
|
|
@@ -1,12 +1,14 @@
|
|
|
1
|
+
import { Edge, EdgeProps } from "@xyflow/react";
|
|
1
2
|
import { FC } from "react";
|
|
2
|
-
import {
|
|
3
|
-
interface
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
};
|
|
3
|
+
import { ChatMessageType } from "../../generated/neuro-san/NeuroSanClient.js";
|
|
4
|
+
interface ThoughtBubbleEdgeData extends Record<string, unknown> {
|
|
5
|
+
text?: string;
|
|
6
|
+
showAlways?: boolean;
|
|
7
|
+
conversationId?: string;
|
|
8
|
+
type?: ChatMessageType;
|
|
9
|
+
agents?: string[];
|
|
10
10
|
}
|
|
11
|
+
export type ThoughtBubbleEdgeShape = Edge<ThoughtBubbleEdgeData, "thoughtBubbleEdge">;
|
|
12
|
+
type ThoughtBubbleEdgeProps = EdgeProps<ThoughtBubbleEdgeShape>;
|
|
11
13
|
export declare const ThoughtBubbleEdge: FC<ThoughtBubbleEdgeProps>;
|
|
12
14
|
export {};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
-
import { getBezierPath } from "
|
|
2
|
+
import { getBezierPath } from "@xyflow/react";
|
|
3
3
|
// Simplified edge component - visual rendering is handled by ThoughtBubbleOverlay
|
|
4
4
|
export const ThoughtBubbleEdge = ({ sourceX, sourceY, targetX, targetY, sourcePosition, targetPosition, data, }) => {
|
|
5
5
|
const conversationId = data?.conversationId || "";
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
+
import type { Node as RFNode } from "@xyflow/react";
|
|
1
2
|
import { FC } from "react";
|
|
2
|
-
import
|
|
3
|
+
import { ThoughtBubbleEdgeShape } from "./ThoughtBubbleEdge.js";
|
|
3
4
|
interface ThoughtBubbleOverlayProps {
|
|
4
5
|
readonly nodes: RFNode[];
|
|
5
|
-
readonly edges:
|
|
6
|
+
readonly edges: ThoughtBubbleEdgeShape[];
|
|
6
7
|
readonly showThoughtBubbles?: boolean;
|
|
7
8
|
readonly isStreaming?: boolean;
|
|
8
9
|
readonly onBubbleHoverChange?: (bubbleId: string | null) => void;
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { styled } from "@mui/material";
|
|
2
|
+
import { styled } from "@mui/material/styles";
|
|
3
3
|
import { Fragment, useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
4
4
|
import { ChatMessageType } from "../../generated/neuro-san/NeuroSanClient.js";
|
|
5
|
-
// Note: Removed BubblePosition interface - no longer needed for right-side positioning
|
|
6
5
|
// #endregion: Types
|
|
7
6
|
// #region: Constants
|
|
8
7
|
const BUBBLE_DISTANCE_FROM_RIGHT_EDGE = 20; // Fixed distance from right edge
|
|
@@ -104,16 +103,14 @@ export const ThoughtBubbleOverlay = ({ nodes, edges, showThoughtBubbles = true,
|
|
|
104
103
|
const mountedRef = useRef(true);
|
|
105
104
|
// Filter edges with meaningful text (memoized to prevent infinite re-renders)
|
|
106
105
|
const thoughtBubbleEdges = useMemo(() => edges.filter((e) => {
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
}
|
|
110
|
-
return e.data.text;
|
|
106
|
+
const text = e.data?.text;
|
|
107
|
+
return typeof text === "string" && text?.length > 0;
|
|
111
108
|
}), [edges]);
|
|
112
109
|
// Find frontman node (depth === 0, similar to isFrontman logic in AgentNode.tsx)
|
|
113
110
|
const frontmanNode = useMemo(() => {
|
|
114
111
|
if (!nodes || !Array.isArray(nodes) || nodes.length === 0)
|
|
115
112
|
return null;
|
|
116
|
-
return nodes.find((n) => n.data
|
|
113
|
+
return nodes.find((n) => n.data["depth"] === 0);
|
|
117
114
|
}, [nodes]);
|
|
118
115
|
// Handle bubble lifecycle (appear/disappear animations)
|
|
119
116
|
useEffect(() => {
|
|
@@ -178,11 +175,11 @@ export const ThoughtBubbleOverlay = ({ nodes, edges, showThoughtBubbles = true,
|
|
|
178
175
|
if (!nodes || !Array.isArray(nodes))
|
|
179
176
|
return set;
|
|
180
177
|
for (const node of nodes) {
|
|
181
|
-
const getConversations = node.data?.getConversations;
|
|
178
|
+
const getConversations = node.data?.["getConversations"];
|
|
182
179
|
if (typeof getConversations === "function") {
|
|
183
180
|
const convs = getConversations();
|
|
184
181
|
if (Array.isArray(convs)) {
|
|
185
|
-
const hasSelf = convs.some((conv) =>
|
|
182
|
+
const hasSelf = convs.some((conv) => conv?.agents?.has?.(node.id));
|
|
186
183
|
if (hasSelf) {
|
|
187
184
|
set.add(node.id);
|
|
188
185
|
}
|
|
@@ -225,7 +222,7 @@ export const ThoughtBubbleOverlay = ({ nodes, edges, showThoughtBubbles = true,
|
|
|
225
222
|
}
|
|
226
223
|
if (bubbleId === null) {
|
|
227
224
|
// Delay clearing the hover state when mouse leaves to prevent accidental unhover
|
|
228
|
-
// "window." to satisfy
|
|
225
|
+
// "window." to satisfy TypeScript
|
|
229
226
|
hoverTimeoutRef.current = window.setTimeout(() => {
|
|
230
227
|
setHoveredBubbleId(null);
|
|
231
228
|
if (onBubbleHoverChange) {
|
|
@@ -263,7 +260,7 @@ export const ThoughtBubbleOverlay = ({ nodes, edges, showThoughtBubbles = true,
|
|
|
263
260
|
bubbleY = BUBBLE_STACK_OFFSET_TOP + bubbleIndex * BUBBLE_HEIGHT_PLUS_SPACING + BUBBLE_HEIGHT / 2;
|
|
264
261
|
}
|
|
265
262
|
// Determine which agents to point to. If the edge supplies an `agents` array in
|
|
266
|
-
// data (provided by AgentFlow), use that. Otherwise fallback to the explicit
|
|
263
|
+
// data (provided by AgentFlow), use that. Otherwise, fallback to the explicit
|
|
267
264
|
// edge.target/edge.source pair (single target).
|
|
268
265
|
let agentIds = Array.isArray(edge.data?.agents)
|
|
269
266
|
? edge.data?.agents
|
|
@@ -338,10 +335,10 @@ export const ThoughtBubbleOverlay = ({ nodes, edges, showThoughtBubbles = true,
|
|
|
338
335
|
catch (err) {
|
|
339
336
|
// Guard against unexpected DOM errors during measurement
|
|
340
337
|
// Do not throw to avoid breaking the app
|
|
341
|
-
console.
|
|
338
|
+
console.error("ThoughtBubbleOverlay: updateAllLines error", err);
|
|
342
339
|
}
|
|
343
340
|
}, [renderableBubbles, bubbleStates, calculateLineCoordinates]);
|
|
344
|
-
// Schedule post-paint updates with rAF and ResizeObserver. Also optionally run a
|
|
341
|
+
// Schedule post-paint updates with rAF and ResizeObserver. Also, optionally run a
|
|
345
342
|
// continuous loop while `isStreaming` is true to keep lines in sync during streaming.
|
|
346
343
|
useEffect(() => {
|
|
347
344
|
mountedRef.current = true;
|
|
@@ -2,6 +2,4 @@ export declare const DEFAULT_FRONTMAN_X_POS = 150;
|
|
|
2
2
|
export declare const DEFAULT_FRONTMAN_Y_POS = 450;
|
|
3
3
|
export declare const BASE_RADIUS = 100;
|
|
4
4
|
export declare const LEVEL_SPACING = 150;
|
|
5
|
-
export declare const
|
|
6
|
-
export declare const BACKGROUND_COLORS_DARK_IDX = 6;
|
|
7
|
-
export declare const HEATMAP_COLORS: string[];
|
|
5
|
+
export declare const TEMPORARY_NETWORK_FOLDER = "temporary";
|
|
@@ -19,21 +19,7 @@ export const DEFAULT_FRONTMAN_Y_POS = 450;
|
|
|
19
19
|
export const BASE_RADIUS = 100;
|
|
20
20
|
// Distance between depth levels
|
|
21
21
|
export const LEVEL_SPACING = 150;
|
|
22
|
-
//
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
"#c6dbef",
|
|
27
|
-
"#9ecae1",
|
|
28
|
-
"#6baed6",
|
|
29
|
-
"#4292c6",
|
|
30
|
-
"#2171b5",
|
|
31
|
-
"#08519c",
|
|
32
|
-
"#08306b",
|
|
33
|
-
"#041c45",
|
|
34
|
-
];
|
|
35
|
-
// Zero-based index of the one where colors start to get dark. Used for displaying contrasting text colors.
|
|
36
|
-
export const BACKGROUND_COLORS_DARK_IDX = 6; // Somewhat subjective
|
|
37
|
-
// Palette for heatmap coloring of nodes
|
|
38
|
-
// For now, use same palette as background colors
|
|
39
|
-
export const HEATMAP_COLORS = BACKGROUND_COLORS;
|
|
22
|
+
// Temporary folder name for networks created from agent reservations. These networks are not "in a folder" when
|
|
23
|
+
// they come from the backend, but we need to put them somewhere in the UI, and this makes it clear that they're
|
|
24
|
+
// temporary.
|
|
25
|
+
export const TEMPORARY_NETWORK_FOLDER = "temporary";
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hook to manage the fading checkmark state.
|
|
3
|
+
*/
|
|
4
|
+
export declare const useCheckmarkFade: () => {
|
|
5
|
+
show: boolean;
|
|
6
|
+
trigger: () => void;
|
|
7
|
+
};
|
|
8
|
+
/**
|
|
9
|
+
* A checkmark that fades in and out based on the `show` prop.
|
|
10
|
+
* @param show Whether to show the checkmark.
|
|
11
|
+
*/
|
|
12
|
+
export declare const FadingCheckmark: ({ show }: {
|
|
13
|
+
show: boolean;
|
|
14
|
+
}) => import("react/jsx-runtime").JSX.Element;
|