impact-chatbot 2.3.82 → 2.3.84
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/dist/components/message-template/components/message-content/StepFormContent.d.ts +5 -1
- package/dist/components/message-template/components/message-content/tabular-content/index.d.ts +4 -1
- package/dist/components/message-template/components/message-types/streamed-content/StreamedContent.d.ts +2 -1
- package/dist/components/message-template/components/message-types/streamed-content/steps-response-tab/components/Steps.d.ts +4 -1
- package/dist/index.cjs.js +250 -103
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.esm.js +250 -103
- package/dist/index.esm.js.map +1 -1
- package/package.json +1 -1
package/dist/index.esm.js
CHANGED
|
@@ -17,9 +17,9 @@ import rehypeSanitize from 'rehype-sanitize';
|
|
|
17
17
|
import remarkBreaks from 'remark-breaks';
|
|
18
18
|
import remarkGfm from 'remark-gfm';
|
|
19
19
|
import DOMPurify from 'dompurify';
|
|
20
|
+
import { useNavigate, useLocation } from 'react-router-dom-v5-compat';
|
|
20
21
|
import { setSelectedFilters, setFilterConfiguration, getFilterUserConfiguration } from 'core/actions/filterAction';
|
|
21
22
|
import { setChatbotContext, setStepFormStreamData, setMinimizedStreamData, setThinkingContext, setPersistedFormValues, clearPersistedFormValues, setCurrentAgentChatId, setHierarchyKeyValue, setChatbotFilterOptions, setSavedFilterSets } from 'core/actions/smartBotActions';
|
|
22
|
-
import { useNavigate, useLocation } from 'react-router-dom-v5-compat';
|
|
23
23
|
import RefreshIcon from '@mui/icons-material/Refresh';
|
|
24
24
|
import styled from 'styled-components';
|
|
25
25
|
import { CircularProgress, Typography, Grid } from '@mui/material';
|
|
@@ -326,9 +326,9 @@ const parseResponse = (data, type, agentId = "", currentMode = "", disableTimeAn
|
|
|
326
326
|
userType: "bot",
|
|
327
327
|
userName: userName,
|
|
328
328
|
bodyText: data?.response,
|
|
329
|
-
headerTitle:
|
|
329
|
+
headerTitle: "",
|
|
330
330
|
thinkingResponse: data?.thinkingResponse,
|
|
331
|
-
noShowHeaderTitle:
|
|
331
|
+
noShowHeaderTitle: true,
|
|
332
332
|
bodyType: "text",
|
|
333
333
|
};
|
|
334
334
|
case "stream":
|
|
@@ -592,7 +592,8 @@ const parseResponse = (data, type, agentId = "", currentMode = "", disableTimeAn
|
|
|
592
592
|
timeStamp: timeString,
|
|
593
593
|
userType: "bot",
|
|
594
594
|
userName: userName,
|
|
595
|
-
headerTitle:
|
|
595
|
+
headerTitle: "",
|
|
596
|
+
noShowHeaderTitle: true,
|
|
596
597
|
bodyType: "image",
|
|
597
598
|
bodyText: data?.image || data,
|
|
598
599
|
};
|
|
@@ -1097,6 +1098,66 @@ const getFormattedApplicationName = (applicationURL) => {
|
|
|
1097
1098
|
}
|
|
1098
1099
|
};
|
|
1099
1100
|
|
|
1101
|
+
/**
|
|
1102
|
+
* Resolves a link href to an in-app route (path + search + hash) when the link
|
|
1103
|
+
* points to a screen of this application, otherwise returns null.
|
|
1104
|
+
* Handles both relative links ("/inventory-smart/create-allocation?step=0") and
|
|
1105
|
+
* absolute links sent by the backend
|
|
1106
|
+
* ("https://tapestry.test.impactsmartsuite.com/inventory-smart/create-allocation?step=0").
|
|
1107
|
+
*/
|
|
1108
|
+
const resolveInternalPath = (href) => {
|
|
1109
|
+
if (!href || typeof href !== 'string')
|
|
1110
|
+
return null;
|
|
1111
|
+
// Non navigational protocols (mailto:, tel:, javascript:, #anchor) stay as-is
|
|
1112
|
+
if (/^(mailto:|tel:|javascript:)/i.test(href) || href.startsWith('#'))
|
|
1113
|
+
return null;
|
|
1114
|
+
try {
|
|
1115
|
+
const url = new URL(href, window.location.origin);
|
|
1116
|
+
if (url.protocol !== 'http:' && url.protocol !== 'https:')
|
|
1117
|
+
return null;
|
|
1118
|
+
const currentApp = window.location.pathname.split('/')[1];
|
|
1119
|
+
const targetApp = url.pathname.split('/')[1];
|
|
1120
|
+
// Same origin, or a different host of the same app (e.g. backend returns the
|
|
1121
|
+
// deployed host while running locally) - both resolve to a client side route
|
|
1122
|
+
const isInternal = url.origin === window.location.origin ||
|
|
1123
|
+
(!!currentApp && currentApp === targetApp);
|
|
1124
|
+
if (!isInternal)
|
|
1125
|
+
return null;
|
|
1126
|
+
return `${url.pathname}${url.search}${url.hash}`;
|
|
1127
|
+
}
|
|
1128
|
+
catch (e) {
|
|
1129
|
+
return null;
|
|
1130
|
+
}
|
|
1131
|
+
};
|
|
1132
|
+
/**
|
|
1133
|
+
* Minimizes the chat window so the user can see the screen they navigated to.
|
|
1134
|
+
* SmartBot (index.tsx) listens for this event and sets partialClose.
|
|
1135
|
+
*/
|
|
1136
|
+
const minimizeChatBot = () => {
|
|
1137
|
+
window.dispatchEvent(new CustomEvent("smartBotMinimize"));
|
|
1138
|
+
};
|
|
1139
|
+
/**
|
|
1140
|
+
* Anchor rendered inside chatbot markdown. Internal links are navigated through
|
|
1141
|
+
* react-router so the chatbot is not remounted by a full page load.
|
|
1142
|
+
*/
|
|
1143
|
+
const MarkdownLink = ({ href, children, ...props }) => {
|
|
1144
|
+
const navigate = useNavigate();
|
|
1145
|
+
const handleClick = (event) => {
|
|
1146
|
+
// Let the browser handle new tab / new window / download intents
|
|
1147
|
+
if (event.metaKey || event.ctrlKey || event.shiftKey || event.altKey || event.button !== 0)
|
|
1148
|
+
return;
|
|
1149
|
+
const internalPath = resolveInternalPath(href);
|
|
1150
|
+
if (!internalPath)
|
|
1151
|
+
return;
|
|
1152
|
+
event.preventDefault();
|
|
1153
|
+
const currentPath = `${window.location.pathname}${window.location.search}`;
|
|
1154
|
+
if (currentPath !== internalPath) {
|
|
1155
|
+
navigate(internalPath);
|
|
1156
|
+
}
|
|
1157
|
+
minimizeChatBot();
|
|
1158
|
+
};
|
|
1159
|
+
return (jsx("a", { href: href, target: "_self", onClick: handleClick, ...props, children: children }));
|
|
1160
|
+
};
|
|
1100
1161
|
/**
|
|
1101
1162
|
* Checks whether the input string contains meaningful HTML markup
|
|
1102
1163
|
* (beyond simple inline tags like <b>, <i>, <em>, <strong>, <br>, <a>, <u>
|
|
@@ -1137,9 +1198,16 @@ const preprocessMarkdown = (content) => {
|
|
|
1137
1198
|
.replace(/(^|\n)([^\n-•]*[a-zA-Z0-9][^\n]*)\n([-•]\s+)/g, '$1$2\n\n$3')
|
|
1138
1199
|
// Handle list items with - or • appearing directly after text without newline
|
|
1139
1200
|
// Only treat as a new bullet when preceded by sentence-ending punctuation (to avoid splitting inline hyphens like "KSO- ORLANDO")
|
|
1140
|
-
|
|
1141
|
-
//
|
|
1142
|
-
.replace(/(\n
|
|
1201
|
+
// [^\S\n] (horizontal whitespace only) keeps this from crossing line breaks,
|
|
1202
|
+
// which would dedent already correctly indented nested bullets
|
|
1203
|
+
.replace(/([.!?:)"])[^\S\n]*([-\u2022])[^\S\n]+/g, '$1\n\n$2 ')
|
|
1204
|
+
// Handle nested list items with proper indentation.
|
|
1205
|
+
// Matching only horizontal whitespace after the newline keeps blank lines and
|
|
1206
|
+
// top level numbered items intact (indenting those turns them into plain text).
|
|
1207
|
+
// Normalize to 3 spaces: enough to nest under both "- " and "1. " parents, and
|
|
1208
|
+
// below the 4 space threshold that would turn the line into a code block.
|
|
1209
|
+
// Indents of 4 or more are left untouched (deliberate deeper nesting).
|
|
1210
|
+
.replace(/(\n[^\S\n]{2,3})([-\u2022]|\d+\.)[^\S\n]+/g, '\n $2 ')
|
|
1143
1211
|
// Ensure double line breaks after list sections
|
|
1144
1212
|
.replace(/(\n\d+\.\s+.*?)(\n\n###)/g, '$1\n$2')
|
|
1145
1213
|
.replace(/(\n[-•]\s+.*?)(\n\n###)/g, '$1\n$2')
|
|
@@ -1151,8 +1219,8 @@ const preprocessMarkdown = (content) => {
|
|
|
1151
1219
|
* Custom components for markdown rendering
|
|
1152
1220
|
*/
|
|
1153
1221
|
const markdownComponents = {
|
|
1154
|
-
// Custom link component that
|
|
1155
|
-
a:
|
|
1222
|
+
// Custom link component that navigates in-app without reloading the page
|
|
1223
|
+
a: MarkdownLink,
|
|
1156
1224
|
// Custom code component
|
|
1157
1225
|
code: ({ children, className, ...props }) => (jsx("code", { className: `markdown-code ${className || ''}`, ...props, children: children })),
|
|
1158
1226
|
// Custom pre component for code blocks
|
|
@@ -1172,13 +1240,32 @@ const markdownComponents = {
|
|
|
1172
1240
|
* Markdown renderer component with sanitization
|
|
1173
1241
|
*/
|
|
1174
1242
|
const TextRenderer = ({ text, thinking }) => {
|
|
1243
|
+
const navigate = useNavigate();
|
|
1244
|
+
// Click delegation for anchors inside raw HTML content (dangerouslySetInnerHTML),
|
|
1245
|
+
// so in-app links navigate through react-router instead of reloading the page.
|
|
1246
|
+
const handleHtmlClick = (event) => {
|
|
1247
|
+
if (event.metaKey || event.ctrlKey || event.shiftKey || event.altKey || event.button !== 0)
|
|
1248
|
+
return;
|
|
1249
|
+
const anchor = event.target.closest?.('a');
|
|
1250
|
+
if (!anchor || anchor.target === '_blank')
|
|
1251
|
+
return;
|
|
1252
|
+
const internalPath = resolveInternalPath(anchor.getAttribute('href'));
|
|
1253
|
+
if (!internalPath)
|
|
1254
|
+
return;
|
|
1255
|
+
event.preventDefault();
|
|
1256
|
+
const currentPath = `${window.location.pathname}${window.location.search}`;
|
|
1257
|
+
if (currentPath !== internalPath) {
|
|
1258
|
+
navigate(internalPath);
|
|
1259
|
+
}
|
|
1260
|
+
minimizeChatBot();
|
|
1261
|
+
};
|
|
1175
1262
|
// If the input contains rich HTML, render it directly with DOMPurify sanitization
|
|
1176
1263
|
if (containsRichHtml(text)) {
|
|
1177
1264
|
const sanitizedHtml = DOMPurify.sanitize(text, {
|
|
1178
1265
|
ADD_TAGS: ['style'],
|
|
1179
1266
|
ADD_ATTR: ['style', 'class', 'target', 'rel'],
|
|
1180
1267
|
});
|
|
1181
|
-
return (jsx("div", { className: `markdown-content md-content ${thinking ? "thinking" : ""}`, dangerouslySetInnerHTML: { __html: sanitizedHtml } }));
|
|
1268
|
+
return (jsx("div", { className: `markdown-content md-content ${thinking ? "thinking" : ""}`, onClick: handleHtmlClick, dangerouslySetInnerHTML: { __html: sanitizedHtml } }));
|
|
1182
1269
|
}
|
|
1183
1270
|
// Otherwise, use the existing markdown pipeline
|
|
1184
1271
|
const processedContent = preprocessMarkdown(text);
|
|
@@ -5009,7 +5096,7 @@ const ChipsContent = ({ bodyText, props }) => {
|
|
|
5009
5096
|
const classes = useStyles$a();
|
|
5010
5097
|
const globalClasses = globalStyles();
|
|
5011
5098
|
return (jsx("div", { className: `${globalClasses.flexRow} ${globalClasses.flexWrap} ${globalClasses.gap} ${globalClasses.verticalAlignCenter}`, children: bodyText.map((data, index) => {
|
|
5012
|
-
const callBack = data.interactable
|
|
5099
|
+
const callBack = data.interactable && props
|
|
5013
5100
|
? Object.entries(props).filter((entry) => entry[0] === data.actionName)?.[0]?.[1]
|
|
5014
5101
|
: null;
|
|
5015
5102
|
return (jsx(Typography, { component: "span", variant: "body1", className: `${classes.gptChips} ${data.interactable ? globalClasses.cursorPointer : ""}`, onClick: () => {
|
|
@@ -5076,7 +5163,7 @@ const QuestionsContent = ({ bodyText, props }) => {
|
|
|
5076
5163
|
};
|
|
5077
5164
|
};
|
|
5078
5165
|
return (jsx("div", { className: `${globalClasses.flexRow} ${globalClasses.flexColumn} ${classes.gptQuestionContainer}`, children: bodyText.map((data, index) => {
|
|
5079
|
-
const callBack = data.interactable
|
|
5166
|
+
const callBack = data.interactable && props
|
|
5080
5167
|
? Object.entries(props).filter((entry) => entry[0] === data.actionName)?.[0]?.[1]
|
|
5081
5168
|
: null;
|
|
5082
5169
|
return (jsxs("div", { className: `${globalClasses.layoutAlignStart} ${classes.gptQuestionBlock}`, style: {
|
|
@@ -6827,6 +6914,36 @@ const fetchCrossFilterOptions = async (filterConfig, existingSelections = [], al
|
|
|
6827
6914
|
}
|
|
6828
6915
|
};
|
|
6829
6916
|
|
|
6917
|
+
const useStyles$6 = makeStyles(() => ({
|
|
6918
|
+
htmlContentContainer: {
|
|
6919
|
+
width: "100%",
|
|
6920
|
+
"& *": {
|
|
6921
|
+
boxSizing: "border-box",
|
|
6922
|
+
},
|
|
6923
|
+
},
|
|
6924
|
+
}));
|
|
6925
|
+
const HtmlContent = ({ bodyText }) => {
|
|
6926
|
+
const classes = useStyles$6();
|
|
6927
|
+
const containerRef = useRef(null);
|
|
6928
|
+
const content = bodyText?.content || "";
|
|
6929
|
+
useEffect(() => {
|
|
6930
|
+
if (containerRef.current && content) {
|
|
6931
|
+
const sanitizedHtml = DOMPurify.sanitize(content, {
|
|
6932
|
+
ADD_TAGS: ["style", "details", "summary"],
|
|
6933
|
+
ADD_ATTR: ["open", "target", "rel", "class", "style"],
|
|
6934
|
+
ALLOW_DATA_ATTR: true,
|
|
6935
|
+
FORCE_BODY: true,
|
|
6936
|
+
WHOLE_DOCUMENT: false,
|
|
6937
|
+
});
|
|
6938
|
+
containerRef.current.innerHTML = sanitizedHtml;
|
|
6939
|
+
}
|
|
6940
|
+
}, [content]);
|
|
6941
|
+
if (!content) {
|
|
6942
|
+
return null;
|
|
6943
|
+
}
|
|
6944
|
+
return (jsx("div", { ref: containerRef, className: classes.htmlContentContainer }));
|
|
6945
|
+
};
|
|
6946
|
+
|
|
6830
6947
|
const SliderContent = ({ bodyText, isFormDisabled = false, messageIndex }) => {
|
|
6831
6948
|
const formKey = `${messageIndex}_${bodyText?.paramName}`;
|
|
6832
6949
|
const { header, headerOrentiation, inputPosition, label, max, min, required, disabled, } = bodyText;
|
|
@@ -7372,8 +7489,9 @@ const STEP_FORM_TIMEOUT_KEY = "__stepFormTimedOut";
|
|
|
7372
7489
|
* @param {Array} props.formData - Array of raw widget_data items from step_form chunk
|
|
7373
7490
|
* @param {number} props.messageIndex - Index for form state persistence keys
|
|
7374
7491
|
*/
|
|
7375
|
-
const StepFormContent = ({ formData, messageIndex = 0, isFormDisabled = false, showSavedFilters = true, preSelectedFilters = null }) => {
|
|
7492
|
+
const StepFormContent = ({ formData, messageIndex = 0, isFormDisabled = false, showSavedFilters = true, preSelectedFilters = null, botProps = null, currentMode = "", agentId = "", sessionId = "", }) => {
|
|
7376
7493
|
const dispatch = useDispatch();
|
|
7494
|
+
const classes = useStyles$a();
|
|
7377
7495
|
const savedFilterSets = useSelector((state) => state.smartBotReducer.savedFilterSets);
|
|
7378
7496
|
const persistedFormValues = useSelector((state) => state.smartBotReducer.persistedFormValues);
|
|
7379
7497
|
const chatbotContext = useSelector((state) => state.smartBotReducer.chatbotContext);
|
|
@@ -7646,7 +7764,11 @@ const StepFormContent = ({ formData, messageIndex = 0, isFormDisabled = false, s
|
|
|
7646
7764
|
case "text":
|
|
7647
7765
|
return jsx(TextContent, { bodyText: parsedData.bodyText, botData: parsedData }, key);
|
|
7648
7766
|
case "chips":
|
|
7649
|
-
return jsx(
|
|
7767
|
+
return parsedData.isMultiSelect ? (jsx(SelectableChips, { bodyText: parsedData.bodyText, chipType: "selectable", utilityData: parsedData.utilityData, props: botProps }, key)) : (jsx(ChipsContent, { bodyText: parsedData.bodyText, props: botProps }, key));
|
|
7768
|
+
case "questions":
|
|
7769
|
+
return jsx(QuestionsContent, { bodyText: parsedData.bodyText, props: botProps }, key);
|
|
7770
|
+
case "html":
|
|
7771
|
+
return jsx(HtmlContent, { bodyText: parsedData.bodyText }, key);
|
|
7650
7772
|
case "table":
|
|
7651
7773
|
return jsx(TableContent, { bodyText: parsedData.bodyText }, key);
|
|
7652
7774
|
case "graph":
|
|
@@ -7677,12 +7799,18 @@ const StepFormContent = ({ formData, messageIndex = 0, isFormDisabled = false, s
|
|
|
7677
7799
|
const buttonItems = [];
|
|
7678
7800
|
formData.forEach((item, index) => {
|
|
7679
7801
|
try {
|
|
7680
|
-
const parsedData = parseResponse(item, item.type,
|
|
7802
|
+
const parsedData = parseResponse(item, item.type, agentId, currentMode, true, sessionId);
|
|
7681
7803
|
if (!parsedData)
|
|
7682
7804
|
return;
|
|
7683
|
-
const
|
|
7684
|
-
if (!
|
|
7805
|
+
const body = renderItem(parsedData, index);
|
|
7806
|
+
if (!body)
|
|
7685
7807
|
return;
|
|
7808
|
+
// Skip the block header when it is just a repeat of the label the widget
|
|
7809
|
+
// renders itself (parseResponse derives headerTitle from label for inputs).
|
|
7810
|
+
const showHeaderTitle = !parsedData?.noShowHeaderTitle &&
|
|
7811
|
+
Boolean(parsedData?.headerTitle?.length) &&
|
|
7812
|
+
parsedData.headerTitle !== parsedData?.bodyText?.label;
|
|
7813
|
+
const rendered = showHeaderTitle ? (jsxs(Fragment$1, { children: [jsx("div", { className: `${classes.chatbotText} ${classes.boldText} ${classes.combinedBlockHeaderTitle}`, children: parsedData.headerTitle }), body] }, `step-form-block-${index}`)) : (body);
|
|
7686
7814
|
if (parsedData.bodyType === "button") {
|
|
7687
7815
|
buttonItems.push(rendered);
|
|
7688
7816
|
}
|
|
@@ -7705,7 +7833,7 @@ const resetStepFormTimeoutFlag = () => {
|
|
|
7705
7833
|
sessionStorage.removeItem(STEP_FORM_TIMEOUT_KEY);
|
|
7706
7834
|
};
|
|
7707
7835
|
|
|
7708
|
-
const useStyles$
|
|
7836
|
+
const useStyles$5 = makeStyles(() => ({
|
|
7709
7837
|
subStepMarkdown: {
|
|
7710
7838
|
// Inherit font styles from parent (.progressSubItem)
|
|
7711
7839
|
fontFamily: 'inherit',
|
|
@@ -7779,14 +7907,14 @@ const preprocessSubStepMarkdown = (content) => {
|
|
|
7779
7907
|
.trim();
|
|
7780
7908
|
};
|
|
7781
7909
|
const SubStepRenderer = ({ text }) => {
|
|
7782
|
-
const classes = useStyles$
|
|
7910
|
+
const classes = useStyles$5();
|
|
7783
7911
|
if (!text)
|
|
7784
7912
|
return null;
|
|
7785
7913
|
const processed = preprocessSubStepMarkdown(text);
|
|
7786
7914
|
return (jsx("div", { className: classes.subStepMarkdown, children: jsx(ReactMarkdown, { remarkPlugins: [remarkGfm, remarkBreaks], children: processed }) }));
|
|
7787
7915
|
};
|
|
7788
7916
|
|
|
7789
|
-
const useStyles$
|
|
7917
|
+
const useStyles$4 = makeStyles$1((theme) => ({
|
|
7790
7918
|
"@global": {
|
|
7791
7919
|
"@keyframes progressDotPulse": {
|
|
7792
7920
|
"0%": {
|
|
@@ -8060,7 +8188,7 @@ const getQuestionStatus$1 = (questionSteps) => {
|
|
|
8060
8188
|
/**
|
|
8061
8189
|
* Renders a single progress bar item (main point + sub-items)
|
|
8062
8190
|
*/
|
|
8063
|
-
const ProgressBarItem$1 = ({ question, questionSteps, isLast, classes, formData, showSavedFilters = true, preSelectedFilters = null, isFormDisabled, onAllSubItemsAnimated = undefined }) => {
|
|
8191
|
+
const ProgressBarItem$1 = ({ question, questionSteps, isLast, classes, formData, showSavedFilters = true, preSelectedFilters = null, isFormDisabled, onAllSubItemsAnimated = undefined, botProps = null, currentMode = "", agentId = "", sessionId = "" }) => {
|
|
8064
8192
|
const status = getQuestionStatus$1(questionSteps);
|
|
8065
8193
|
const animatedCountRef = useRef(0);
|
|
8066
8194
|
const [isExpanded, setIsExpanded] = useState(true);
|
|
@@ -8094,10 +8222,10 @@ const ProgressBarItem$1 = ({ question, questionSteps, isLast, classes, formData,
|
|
|
8094
8222
|
if (animatedCountRef.current >= arr.length && onAllSubItemsAnimated) {
|
|
8095
8223
|
onAllSubItemsAnimated();
|
|
8096
8224
|
}
|
|
8097
|
-
} }) }, idx))) })), formData && isExpanded && (jsx("div", { className: classes.stepFormContainer, children: jsx(StepFormContent, { formData: formData, isFormDisabled: isFormDisabled, showSavedFilters: showSavedFilters, preSelectedFilters: preSelectedFilters }) }))] })] }));
|
|
8225
|
+
} }) }, idx))) })), formData && isExpanded && (jsx("div", { className: classes.stepFormContainer, children: jsx(StepFormContent, { formData: formData, isFormDisabled: isFormDisabled, showSavedFilters: showSavedFilters, preSelectedFilters: preSelectedFilters, botProps: botProps, currentMode: currentMode, agentId: agentId, sessionId: sessionId }) }))] })] }));
|
|
8098
8226
|
};
|
|
8099
|
-
const Steps$1 = ({ steps, setSteps, done, setTabValue, setDone, finalStepDone, setFinalStepDone, stepChange, currentMode, questions = [], questionsStepsMap = {}, stepFormDataMap = {}, isFormDisabled = false, }) => {
|
|
8100
|
-
const classes = useStyles$
|
|
8227
|
+
const Steps$1 = ({ steps, setSteps, done, setTabValue, setDone, finalStepDone, setFinalStepDone, stepChange, currentMode, questions = [], questionsStepsMap = {}, stepFormDataMap = {}, isFormDisabled = false, botProps = null, agentId = "", sessionId = "", }) => {
|
|
8228
|
+
const classes = useStyles$4();
|
|
8101
8229
|
useState(false);
|
|
8102
8230
|
const [showThinking, setShowThinking] = useState(false);
|
|
8103
8231
|
// Determine if last question is fully completed (all sub-steps done)
|
|
@@ -8179,7 +8307,7 @@ const Steps$1 = ({ steps, setSteps, done, setTabValue, setDone, finalStepDone, s
|
|
|
8179
8307
|
const showSavedFilters = formEntry && !Array.isArray(formEntry) ? formEntry.showSavedFilters : true;
|
|
8180
8308
|
const preSelectedFilters = formEntry && !Array.isArray(formEntry) ? formEntry.preSelectedFilters : null;
|
|
8181
8309
|
const isLast = index === questions.length - 1;
|
|
8182
|
-
return (jsx(ProgressBarItem$1, { question: question, questionSteps: questionSteps, isLast: isLast && !showThinking, classes: classes, formData: formData, isFormDisabled: isFormDisabled, showSavedFilters: showSavedFilters, preSelectedFilters: preSelectedFilters, onAllSubItemsAnimated: isLast && lastQuestionCompleted && !done
|
|
8310
|
+
return (jsx(ProgressBarItem$1, { question: question, questionSteps: questionSteps, isLast: isLast && !showThinking, classes: classes, formData: formData, isFormDisabled: isFormDisabled, showSavedFilters: showSavedFilters, preSelectedFilters: preSelectedFilters, botProps: botProps, currentMode: currentMode, agentId: agentId, sessionId: sessionId, onAllSubItemsAnimated: isLast && lastQuestionCompleted && !done
|
|
8183
8311
|
? () => setShowThinking(true)
|
|
8184
8312
|
: undefined }, index));
|
|
8185
8313
|
}), showThinking && !done && (jsx("div", { style: {
|
|
@@ -8187,36 +8315,6 @@ const Steps$1 = ({ steps, setSteps, done, setTabValue, setDone, finalStepDone, s
|
|
|
8187
8315
|
}, children: jsx(ProgressBarItem$1, { question: "Thinking", questionSteps: [{ header: "", sub_header: "", step_status: "not-completed" }], isLast: true, classes: classes, formData: null, isFormDisabled: isFormDisabled }) }))] }));
|
|
8188
8316
|
};
|
|
8189
8317
|
|
|
8190
|
-
const useStyles$4 = makeStyles(() => ({
|
|
8191
|
-
htmlContentContainer: {
|
|
8192
|
-
width: "100%",
|
|
8193
|
-
"& *": {
|
|
8194
|
-
boxSizing: "border-box",
|
|
8195
|
-
},
|
|
8196
|
-
},
|
|
8197
|
-
}));
|
|
8198
|
-
const HtmlContent = ({ bodyText }) => {
|
|
8199
|
-
const classes = useStyles$4();
|
|
8200
|
-
const containerRef = useRef(null);
|
|
8201
|
-
const content = bodyText?.content || "";
|
|
8202
|
-
useEffect(() => {
|
|
8203
|
-
if (containerRef.current && content) {
|
|
8204
|
-
const sanitizedHtml = DOMPurify.sanitize(content, {
|
|
8205
|
-
ADD_TAGS: ["style", "details", "summary"],
|
|
8206
|
-
ADD_ATTR: ["open", "target", "rel", "class", "style"],
|
|
8207
|
-
ALLOW_DATA_ATTR: true,
|
|
8208
|
-
FORCE_BODY: true,
|
|
8209
|
-
WHOLE_DOCUMENT: false,
|
|
8210
|
-
});
|
|
8211
|
-
containerRef.current.innerHTML = sanitizedHtml;
|
|
8212
|
-
}
|
|
8213
|
-
}, [content]);
|
|
8214
|
-
if (!content) {
|
|
8215
|
-
return null;
|
|
8216
|
-
}
|
|
8217
|
-
return (jsx("div", { ref: containerRef, className: classes.htmlContentContainer }));
|
|
8218
|
-
};
|
|
8219
|
-
|
|
8220
8318
|
const renderWidgetItem = (item, index, isFormDisabled) => {
|
|
8221
8319
|
try {
|
|
8222
8320
|
const parsedData = parseResponse(item, item.type, "", "", true);
|
|
@@ -8268,7 +8366,7 @@ const AgentResponse$1 = (props) => {
|
|
|
8268
8366
|
};
|
|
8269
8367
|
|
|
8270
8368
|
const StepsResponseTab = (props) => {
|
|
8271
|
-
const { steps, setSteps, stepsDone, setStepsDone, finalStepDone, setFinalStepDone, content, isStreaming, stepChange, currentMode, questions, questionsStepsMap, stepFormDataMap, isFormDisabled, streamingWidgetData, isRetrying, } = props;
|
|
8369
|
+
const { steps, setSteps, stepsDone, setStepsDone, finalStepDone, setFinalStepDone, content, isStreaming, stepChange, currentMode, questions, questionsStepsMap, stepFormDataMap, isFormDisabled, streamingWidgetData, isRetrying, botProps, agentId, sessionId, } = props;
|
|
8272
8370
|
const dispatch = useDispatch();
|
|
8273
8371
|
const thinkingContext = useSelector((state) => state.smartBotReducer.thinkingContext);
|
|
8274
8372
|
const streamStartTimeRef = useRef(thinkingContext?.streamStartTime);
|
|
@@ -8332,7 +8430,7 @@ const StepsResponseTab = (props) => {
|
|
|
8332
8430
|
icon: jsx(PsychologyOutlinedIcon, { fontSize: "large" }),
|
|
8333
8431
|
},
|
|
8334
8432
|
], tabPanels: [
|
|
8335
|
-
jsx(Steps$1, { steps: steps, setSteps: setSteps, done: stepsDone, setDone: setStepsDone, setTabValue: setTabValue, finalStepDone: finalStepDone, setFinalStepDone: setFinalStepDone, stepChange: stepChange, currentMode: currentMode, questions: questions, questionsStepsMap: questionsStepsMap, stepFormDataMap: stepFormDataMap, isFormDisabled: isFormDisabled || isTimedOut }),
|
|
8433
|
+
jsx(Steps$1, { steps: steps, setSteps: setSteps, done: stepsDone, setDone: setStepsDone, setTabValue: setTabValue, finalStepDone: finalStepDone, setFinalStepDone: setFinalStepDone, stepChange: stepChange, currentMode: currentMode, questions: questions, questionsStepsMap: questionsStepsMap, stepFormDataMap: stepFormDataMap, isFormDisabled: isFormDisabled || isTimedOut, botProps: botProps, agentId: agentId, sessionId: sessionId }),
|
|
8336
8434
|
jsxs(Fragment, { children: [jsx(AgentResponse$1, { content: content, isStreaming: isStreaming, streamingWidgetData: streamingWidgetData, isFormDisabled: isFormDisabled || isTimedOut }), timeoutMessage && (jsx("div", { style: { marginTop: "8px", padding: "0 8px" }, children: jsx(TextRenderer, { text: timeoutMessage, thinking: "" }) }))] }),
|
|
8337
8435
|
], value: tabValue }) }));
|
|
8338
8436
|
};
|
|
@@ -8514,7 +8612,7 @@ const streamStateMap = new Map();
|
|
|
8514
8612
|
* @param {React.RefObject} botData.utilityObject.chatBodyRef - Ref to chat body element
|
|
8515
8613
|
* @param {Function} botData.utilityObject.setChatDataState - Function to update chat data state
|
|
8516
8614
|
*/
|
|
8517
|
-
const StreamedContent = ({ botData }) => {
|
|
8615
|
+
const StreamedContent = ({ botData, botProps }) => {
|
|
8518
8616
|
const { activeConversationId, currentMode, chatDataRef, chatBodyRef, setChatDataState, chatDataInfoRef, setLoader = (params) => { }, processResponse = (params) => { }, setThinkingContent, thinkingContent, isThinking: isThinkingFromParent, setIsThinking: setIsThinkingFromParent, chatId, setChatId, isStop, setIsStop, functionsRef, functionsState, setFunctionsState, thinkingHeaderMessage, setThinkingHeaderMessage, baseUrl, setNavSessionId } = botData.utilityObject || {};
|
|
8519
8617
|
const classes = useStyles$7();
|
|
8520
8618
|
useStyles$a();
|
|
@@ -9693,8 +9791,13 @@ const StreamedContent = ({ botData }) => {
|
|
|
9693
9791
|
}, 1000);
|
|
9694
9792
|
}
|
|
9695
9793
|
}, [isStreamingDone, thinkingTime, activeConversationId]);
|
|
9794
|
+
// Show/hide the stop (cancel execution) icon while the stream is active.
|
|
9795
|
+
// Gate on state only - sourceRef is a ref, so mutating it never re-runs this
|
|
9796
|
+
// effect. Relying on it meant that if the source wasn't assigned yet on the
|
|
9797
|
+
// first run, isStop was set to false and never re-evaluated for the rest of
|
|
9798
|
+
// the stream, leaving the cancel button hidden.
|
|
9696
9799
|
useEffect(() => {
|
|
9697
|
-
if (
|
|
9800
|
+
if (isStreaming && !isStreamingDone) {
|
|
9698
9801
|
setIsStop(true);
|
|
9699
9802
|
setFunctionsState({
|
|
9700
9803
|
...functionsState,
|
|
@@ -9705,7 +9808,7 @@ const StreamedContent = ({ botData }) => {
|
|
|
9705
9808
|
else {
|
|
9706
9809
|
setIsStop(false);
|
|
9707
9810
|
}
|
|
9708
|
-
}, [isStreaming]);
|
|
9811
|
+
}, [isStreaming, isStreamingDone]);
|
|
9709
9812
|
/**
|
|
9710
9813
|
* Aborts the current streaming connection
|
|
9711
9814
|
*/
|
|
@@ -9718,10 +9821,12 @@ const StreamedContent = ({ botData }) => {
|
|
|
9718
9821
|
setRetryCountdown(0);
|
|
9719
9822
|
}
|
|
9720
9823
|
retryCountRef.current = MAX_RETRY_COUNT; // Exhaust retries so no further auto-retries happen
|
|
9721
|
-
if (
|
|
9824
|
+
if (isStreaming) {
|
|
9722
9825
|
setWasStreamingAborted(true);
|
|
9723
9826
|
wasStreamingAbortedRef.current = true;
|
|
9724
|
-
sourceRef.current
|
|
9827
|
+
if (sourceRef.current) {
|
|
9828
|
+
sourceRef.current.close();
|
|
9829
|
+
}
|
|
9725
9830
|
setIsStreaming(false);
|
|
9726
9831
|
setIsStreamingDone(true);
|
|
9727
9832
|
// Mark as completed+aborted so tab-switch remounts don't restart the stream.
|
|
@@ -9881,7 +9986,7 @@ const StreamedContent = ({ botData }) => {
|
|
|
9881
9986
|
* @returns {JSX.Element} Rendered content with optional blinking cursor
|
|
9882
9987
|
*/
|
|
9883
9988
|
const renderContent = () => {
|
|
9884
|
-
return (jsxs("div", { className: classes.streamContainer, children: [jsx(StepsResponseTab, { steps: steps, stepChange: stepChange, setSteps: setSteps, stepsDone: stepsDone, setStepsDone: setStepsDone, finalStepDone: finalStepDone, setFinalStepDone: setFinalStepDone, content: content, isStreaming: isStreaming, currentMode: currentMode, questions: questions, questionsStepsMap: questionsStepsMap, stepFormDataMap: stepFormDataMap, isFormDisabled: botData?.isFormDisabled || false, streamingWidgetData: streamingWidgetData, isRetrying: isRetrying }), isRetrying && (jsx("div", { className: classes.retryContainer, children: jsx(TextRenderer, { text: `Auto re-trying in ${retryCountdown}s`, thinking: "" }) }))] }));
|
|
9989
|
+
return (jsxs("div", { className: classes.streamContainer, children: [jsx(StepsResponseTab, { steps: steps, stepChange: stepChange, setSteps: setSteps, stepsDone: stepsDone, setStepsDone: setStepsDone, finalStepDone: finalStepDone, setFinalStepDone: setFinalStepDone, content: content, isStreaming: isStreaming, currentMode: currentMode, questions: questions, questionsStepsMap: questionsStepsMap, stepFormDataMap: stepFormDataMap, isFormDisabled: botData?.isFormDisabled || false, streamingWidgetData: streamingWidgetData, isRetrying: isRetrying, botProps: botProps, agentId: botData?.inputBody?.agent_id || "", sessionId: messageToStoreRef.current?.sessionId || "" }), isRetrying && (jsx("div", { className: classes.retryContainer, children: jsx(TextRenderer, { text: `Auto re-trying in ${retryCountdown}s`, thinking: "" }) }))] }));
|
|
9885
9990
|
};
|
|
9886
9991
|
if (currentMode === "agent") {
|
|
9887
9992
|
return renderContent();
|
|
@@ -10151,8 +10256,9 @@ const AgentResponse = ({ children }) => {
|
|
|
10151
10256
|
// Only the active instance should process stepFormStreamData from Redux.
|
|
10152
10257
|
let instanceCounter = 0;
|
|
10153
10258
|
let activeTabularInstanceId = null;
|
|
10154
|
-
const TabularContent = ({ steps: initialSteps, currentTabValue, children, questions: initialQuestions = [], questionsStepsMap: initialQuestionsStepsMap = {}, stepFormDataMap: initialStepFormDataMap = {}, isFormDisabled = false, sessionId: propSessionId = "" }) => {
|
|
10259
|
+
const TabularContent = ({ steps: initialSteps, currentTabValue, children, questions: initialQuestions = [], questionsStepsMap: initialQuestionsStepsMap = {}, stepFormDataMap: initialStepFormDataMap = {}, isFormDisabled = false, sessionId: propSessionId = "", botProps = null, currentMode = "", agentId = "" }) => {
|
|
10155
10260
|
const dispatch = useDispatch();
|
|
10261
|
+
const chatClasses = useStyles$a();
|
|
10156
10262
|
const stepFormStreamData = useSelector((state) => state.smartBotReducer.stepFormStreamData);
|
|
10157
10263
|
const thinkingContext = useSelector((state) => state.smartBotReducer.thinkingContext);
|
|
10158
10264
|
const streamStartTimeRef = useRef(thinkingContext?.streamStartTime);
|
|
@@ -10236,40 +10342,55 @@ const TabularContent = ({ steps: initialSteps, currentTabValue, children, questi
|
|
|
10236
10342
|
};
|
|
10237
10343
|
}, []);
|
|
10238
10344
|
// Render a widget item from SSE data
|
|
10345
|
+
const renderWidgetBody = (parsedData, key) => {
|
|
10346
|
+
switch (parsedData.bodyType) {
|
|
10347
|
+
case "text":
|
|
10348
|
+
return jsx(TextContent, { bodyText: parsedData.bodyText, botData: parsedData }, key);
|
|
10349
|
+
case "chips":
|
|
10350
|
+
return parsedData.isMultiSelect ? (jsx(SelectableChips, { bodyText: parsedData.bodyText, chipType: "selectable", utilityData: parsedData.utilityData, props: botProps }, key)) : (jsx(ChipsContent, { bodyText: parsedData.bodyText, props: botProps }, key));
|
|
10351
|
+
case "questions":
|
|
10352
|
+
return jsx(QuestionsContent, { bodyText: parsedData.bodyText, props: botProps }, key);
|
|
10353
|
+
case "image":
|
|
10354
|
+
return jsx(ImageContent, { bodyText: parsedData.bodyText }, key);
|
|
10355
|
+
case "table":
|
|
10356
|
+
return jsx(TableContent, { bodyText: parsedData.bodyText }, key);
|
|
10357
|
+
case "graph":
|
|
10358
|
+
return jsx(GraphContent, { bodyText: parsedData.bodyText }, key);
|
|
10359
|
+
case "radio":
|
|
10360
|
+
return jsx(RadioContent, { bodyText: parsedData.bodyText, isFormDisabled: isFormDisabled }, key);
|
|
10361
|
+
case "checkbox":
|
|
10362
|
+
return jsx(CheckboxContent, { bodyText: parsedData.bodyText, isFormDisabled: isFormDisabled }, key);
|
|
10363
|
+
case "select":
|
|
10364
|
+
return jsx(SelectContent, { bodyText: parsedData.bodyText, isFormDisabled: isFormDisabled }, key);
|
|
10365
|
+
case "slider":
|
|
10366
|
+
return jsx(SliderContent, { bodyText: parsedData.bodyText, isFormDisabled: isFormDisabled }, key);
|
|
10367
|
+
case "button":
|
|
10368
|
+
return jsx(ButtonContent, { bodyText: parsedData.bodyText, isFormDisabled: isFormDisabled }, key);
|
|
10369
|
+
case "input":
|
|
10370
|
+
return jsx(InputContent, { bodyText: parsedData.bodyText, isFormDisabled: isFormDisabled }, key);
|
|
10371
|
+
case "datePicker":
|
|
10372
|
+
return jsx(DatePickerContent, { bodyText: parsedData.bodyText, isFormDisabled: isFormDisabled }, key);
|
|
10373
|
+
case "dateRangePicker":
|
|
10374
|
+
return jsx(DateRangePickerContent, { bodyText: parsedData.bodyText, isFormDisabled: isFormDisabled }, key);
|
|
10375
|
+
case "html":
|
|
10376
|
+
return jsx(HtmlContent, { bodyText: parsedData.bodyText }, key);
|
|
10377
|
+
default:
|
|
10378
|
+
return null;
|
|
10379
|
+
}
|
|
10380
|
+
};
|
|
10239
10381
|
const renderWidget = (item, index) => {
|
|
10240
10382
|
try {
|
|
10241
|
-
const parsedData = parseResponse(item, item.type,
|
|
10383
|
+
const parsedData = parseResponse(item, item.type, agentId, currentMode, true, propSessionId);
|
|
10242
10384
|
if (!parsedData)
|
|
10243
10385
|
return null;
|
|
10244
10386
|
const key = `restream-widget-${index}`;
|
|
10245
|
-
|
|
10246
|
-
|
|
10247
|
-
|
|
10248
|
-
|
|
10249
|
-
|
|
10250
|
-
|
|
10251
|
-
|
|
10252
|
-
case "radio":
|
|
10253
|
-
return jsx(RadioContent, { bodyText: parsedData.bodyText, isFormDisabled: isFormDisabled }, key);
|
|
10254
|
-
case "checkbox":
|
|
10255
|
-
return jsx(CheckboxContent, { bodyText: parsedData.bodyText, isFormDisabled: isFormDisabled }, key);
|
|
10256
|
-
case "select":
|
|
10257
|
-
return jsx(SelectContent, { bodyText: parsedData.bodyText, isFormDisabled: isFormDisabled }, key);
|
|
10258
|
-
case "slider":
|
|
10259
|
-
return jsx(SliderContent, { bodyText: parsedData.bodyText, isFormDisabled: isFormDisabled }, key);
|
|
10260
|
-
case "button":
|
|
10261
|
-
return jsx(ButtonContent, { bodyText: parsedData.bodyText, isFormDisabled: isFormDisabled }, key);
|
|
10262
|
-
case "input":
|
|
10263
|
-
return jsx(InputContent, { bodyText: parsedData.bodyText, isFormDisabled: isFormDisabled }, key);
|
|
10264
|
-
case "datePicker":
|
|
10265
|
-
return jsx(DatePickerContent, { bodyText: parsedData.bodyText, isFormDisabled: isFormDisabled }, key);
|
|
10266
|
-
case "dateRangePicker":
|
|
10267
|
-
return jsx(DateRangePickerContent, { bodyText: parsedData.bodyText, isFormDisabled: isFormDisabled }, key);
|
|
10268
|
-
case "html":
|
|
10269
|
-
return jsx(HtmlContent, { bodyText: parsedData.bodyText }, key);
|
|
10270
|
-
default:
|
|
10271
|
-
return null;
|
|
10272
|
-
}
|
|
10387
|
+
const body = renderWidgetBody(parsedData, key);
|
|
10388
|
+
if (!body)
|
|
10389
|
+
return null;
|
|
10390
|
+
const showHeaderTitle = !parsedData?.noShowHeaderTitle && Boolean(parsedData?.headerTitle?.length);
|
|
10391
|
+
if (!showHeaderTitle)
|
|
10392
|
+
return body;
|
|
10393
|
+
return (jsxs(Fragment$1, { children: [jsx("div", { className: `${chatClasses.chatbotText} ${chatClasses.boldText} ${chatClasses.combinedBlockHeaderTitle}`, children: parsedData.headerTitle }), body] }, `restream-widget-block-${index}`));
|
|
10273
10394
|
}
|
|
10274
10395
|
catch (e) {
|
|
10275
10396
|
console.error("[TabularContent] renderWidget error:", e);
|
|
@@ -10639,11 +10760,8 @@ const CombinedContent = ({ botData, props }) => {
|
|
|
10639
10760
|
// Get the array of content items from bodyText
|
|
10640
10761
|
const contentItems = Array.isArray(botData.bodyText) ? botData.bodyText : [];
|
|
10641
10762
|
// Renders the optional block-level header title above a content item.
|
|
10642
|
-
// Text blocks are skipped because their heading is the echoed user query
|
|
10643
|
-
// (response_heading), which we don't want to duplicate in the response.
|
|
10644
10763
|
const renderHeaderTitle = (parsedData) => {
|
|
10645
|
-
const showHeaderTitle = parsedData?.
|
|
10646
|
-
!parsedData?.noShowHeaderTitle &&
|
|
10764
|
+
const showHeaderTitle = !parsedData?.noShowHeaderTitle &&
|
|
10647
10765
|
Boolean(parsedData?.headerTitle?.length);
|
|
10648
10766
|
if (!showHeaderTitle)
|
|
10649
10767
|
return null;
|
|
@@ -10713,7 +10831,7 @@ const CombinedContent = ({ botData, props }) => {
|
|
|
10713
10831
|
const validContent = renderedContent.filter(content => content !== null);
|
|
10714
10832
|
const renderCombinedContent = () => (jsx("div", { className: "combined-content-container", children: validContent.length > 0 ? (validContent.map((content, index) => (jsx("div", { className: "combined-content-item", children: content }, `wrapper-${index}`)))) : (jsx("div", { children: "No valid content to display" })) }));
|
|
10715
10833
|
if (isTabEnabled) {
|
|
10716
|
-
return (jsx(TabularContent, { steps: botData?.utilityData?.steps || [], currentTabValue: botData?.utilityData?.currentTabValue || "steps", questions: botData?.utilityData?.questions || [], questionsStepsMap: botData?.utilityData?.questionsStepsMap || {}, stepFormDataMap: botData?.utilityData?.stepFormDataMap || {}, isFormDisabled: isFormDisabled, sessionId: botData?.sessionId || "", children: renderCombinedContent() }));
|
|
10834
|
+
return (jsx(TabularContent, { steps: botData?.utilityData?.steps || [], currentTabValue: botData?.utilityData?.currentTabValue || "steps", questions: botData?.utilityData?.questions || [], questionsStepsMap: botData?.utilityData?.questionsStepsMap || {}, stepFormDataMap: botData?.utilityData?.stepFormDataMap || {}, isFormDisabled: isFormDisabled, sessionId: botData?.sessionId || "", botProps: props, currentMode: botData?.currentMode || "", agentId: botData?.agentId || "", children: renderCombinedContent() }));
|
|
10717
10835
|
}
|
|
10718
10836
|
return renderCombinedContent();
|
|
10719
10837
|
};
|
|
@@ -10752,7 +10870,7 @@ const BotMessage = ({ botData, state, handleLikeDislike, props }) => {
|
|
|
10752
10870
|
case "text":
|
|
10753
10871
|
return jsx(TextContent, { bodyText: botData.bodyText, botData: botData });
|
|
10754
10872
|
case "stream":
|
|
10755
|
-
return jsx(StreamedContent, { botData: botData });
|
|
10873
|
+
return jsx(StreamedContent, { botData: botData, botProps: props });
|
|
10756
10874
|
case "chips":
|
|
10757
10875
|
if (botData.isMultiSelect) {
|
|
10758
10876
|
return (jsx(SelectableChips, { bodyText: botData.bodyText, utilityData: botData.utilityData, props: props }));
|
|
@@ -14999,13 +15117,19 @@ const SmartBot = (props) => {
|
|
|
14999
15117
|
if (newChatId !== undefined)
|
|
15000
15118
|
setUniqueChatId(newChatId);
|
|
15001
15119
|
};
|
|
15120
|
+
// Minimize the chat window when the user follows an in-app link from a bot response
|
|
15121
|
+
const handleMinimizeRequest = () => {
|
|
15122
|
+
setPartialClose(true);
|
|
15123
|
+
};
|
|
15002
15124
|
window.addEventListener("stepFormStreamStart", handleStepFormStreamStart);
|
|
15003
15125
|
window.addEventListener("stepFormStreamEnd", handleStepFormStreamEnd);
|
|
15004
15126
|
window.addEventListener("stepFormInitStateUpdate", handleStepFormInitStateUpdate);
|
|
15127
|
+
window.addEventListener("smartBotMinimize", handleMinimizeRequest);
|
|
15005
15128
|
return () => {
|
|
15006
15129
|
window.removeEventListener("stepFormStreamStart", handleStepFormStreamStart);
|
|
15007
15130
|
window.removeEventListener("stepFormStreamEnd", handleStepFormStreamEnd);
|
|
15008
15131
|
window.removeEventListener("stepFormInitStateUpdate", handleStepFormInitStateUpdate);
|
|
15132
|
+
window.removeEventListener("smartBotMinimize", handleMinimizeRequest);
|
|
15009
15133
|
};
|
|
15010
15134
|
}, []);
|
|
15011
15135
|
const fetchCustomBotConfigurations = async () => {
|
|
@@ -15141,6 +15265,13 @@ const SmartBot = (props) => {
|
|
|
15141
15265
|
// );
|
|
15142
15266
|
// return;
|
|
15143
15267
|
// } else {
|
|
15268
|
+
// The library re-fires the `initialClick` tab's onClick from an
|
|
15269
|
+
// effect whose deps (tabList/menuItems/onChatBotResize) are
|
|
15270
|
+
// recreated on every render. Track the previous tab so we only
|
|
15271
|
+
// reset transient state on a real tab change - otherwise these
|
|
15272
|
+
// spurious re-invocations wipe isStop mid-stream and hide the
|
|
15273
|
+
// cancel execution button.
|
|
15274
|
+
const previousActiveTab = activeTab.current.activeTab;
|
|
15144
15275
|
setShowSavedFilters(false);
|
|
15145
15276
|
const agentConversations = chatDataInfoRef?.current[params?.name?.toLowerCase()]?.conversations;
|
|
15146
15277
|
const firstConversationId = agentConversations ? Object.keys(agentConversations)[0] : undefined;
|
|
@@ -15159,7 +15290,9 @@ const SmartBot = (props) => {
|
|
|
15159
15290
|
localStorage.setItem("currentModeData", params?.name?.toLowerCase());
|
|
15160
15291
|
setNewChatScreen(false);
|
|
15161
15292
|
activeTab.current.activeTab = "agent";
|
|
15162
|
-
|
|
15293
|
+
if (previousActiveTab !== "agent") {
|
|
15294
|
+
setIsStop(false);
|
|
15295
|
+
}
|
|
15163
15296
|
// }
|
|
15164
15297
|
// setConversation([]);
|
|
15165
15298
|
// chatDataInfoRef.current[currentMode] = [];
|
|
@@ -15178,6 +15311,8 @@ const SmartBot = (props) => {
|
|
|
15178
15311
|
// );
|
|
15179
15312
|
// return;
|
|
15180
15313
|
// } else {
|
|
15314
|
+
// Only reset transient state on a real tab change.
|
|
15315
|
+
const previousActiveTab = activeTab.current.activeTab;
|
|
15181
15316
|
setShowSavedFilters(false);
|
|
15182
15317
|
let currentModeValue = params?.name?.toLowerCase();
|
|
15183
15318
|
const modeConversations = chatDataInfoRef?.current[currentModeValue]?.conversations;
|
|
@@ -15201,7 +15336,9 @@ const SmartBot = (props) => {
|
|
|
15201
15336
|
chatDataInfoRef.current = cloneDeep(parsedData);
|
|
15202
15337
|
}
|
|
15203
15338
|
// setNewChatScreen(true);
|
|
15204
|
-
|
|
15339
|
+
if (previousActiveTab !== "navigation") {
|
|
15340
|
+
setIsStop(false);
|
|
15341
|
+
}
|
|
15205
15342
|
setCurrentMode(params?.name?.toLowerCase());
|
|
15206
15343
|
if (firstConversationId) {
|
|
15207
15344
|
setActiveConversationId(firstConversationId);
|
|
@@ -15270,6 +15407,9 @@ const SmartBot = (props) => {
|
|
|
15270
15407
|
// );
|
|
15271
15408
|
// return;
|
|
15272
15409
|
// } else {
|
|
15410
|
+
// Only reset transient state on a real tab change - the library
|
|
15411
|
+
// re-fires this initialClick handler on every render.
|
|
15412
|
+
const previousActiveTab = activeTab.current.activeTab;
|
|
15273
15413
|
setShowSavedFilters(false);
|
|
15274
15414
|
let currentModeValue = params?.name?.toLowerCase();
|
|
15275
15415
|
const modeConversations = chatDataInfoRef?.current[currentModeValue]?.conversations;
|
|
@@ -15293,7 +15433,9 @@ const SmartBot = (props) => {
|
|
|
15293
15433
|
chatDataInfoRef.current = cloneDeep(parsedData);
|
|
15294
15434
|
}
|
|
15295
15435
|
// setNewChatScreen(true);
|
|
15296
|
-
|
|
15436
|
+
if (previousActiveTab !== "navigation") {
|
|
15437
|
+
setIsStop(false);
|
|
15438
|
+
}
|
|
15297
15439
|
setCurrentMode(params?.name?.toLowerCase());
|
|
15298
15440
|
if (firstConversationId) {
|
|
15299
15441
|
setActiveConversationId(firstConversationId);
|
|
@@ -15324,6 +15466,9 @@ const SmartBot = (props) => {
|
|
|
15324
15466
|
// );
|
|
15325
15467
|
// return;
|
|
15326
15468
|
// } else {
|
|
15469
|
+
// Only reset transient state on a real tab change - the library
|
|
15470
|
+
// re-fires this initialClick handler on every render.
|
|
15471
|
+
const previousActiveTab = activeTab.current.activeTab;
|
|
15327
15472
|
setShowSavedFilters(false);
|
|
15328
15473
|
let currentModeValue = params?.name?.toLowerCase();
|
|
15329
15474
|
const modeConversations = chatDataInfoRef?.current[currentModeValue]?.conversations;
|
|
@@ -15347,7 +15492,9 @@ const SmartBot = (props) => {
|
|
|
15347
15492
|
chatDataInfoRef.current = cloneDeep(parsedData);
|
|
15348
15493
|
}
|
|
15349
15494
|
// setNewChatScreen(true);
|
|
15350
|
-
|
|
15495
|
+
if (previousActiveTab !== "navigation") {
|
|
15496
|
+
setIsStop(false);
|
|
15497
|
+
}
|
|
15351
15498
|
setCurrentMode(params?.name?.toLowerCase());
|
|
15352
15499
|
if (firstConversationId) {
|
|
15353
15500
|
setActiveConversationId(firstConversationId);
|