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.cjs.js
CHANGED
|
@@ -20,9 +20,9 @@ var rehypeSanitize = require('rehype-sanitize');
|
|
|
20
20
|
var remarkBreaks = require('remark-breaks');
|
|
21
21
|
var remarkGfm = require('remark-gfm');
|
|
22
22
|
var DOMPurify = require('dompurify');
|
|
23
|
+
var reactRouterDomV5Compat = require('react-router-dom-v5-compat');
|
|
23
24
|
var filterAction = require('core/actions/filterAction');
|
|
24
25
|
var smartBotActions = require('core/actions/smartBotActions');
|
|
25
|
-
var reactRouterDomV5Compat = require('react-router-dom-v5-compat');
|
|
26
26
|
var RefreshIcon = require('@mui/icons-material/Refresh');
|
|
27
27
|
var styled = require('styled-components');
|
|
28
28
|
var material = require('@mui/material');
|
|
@@ -348,9 +348,9 @@ const parseResponse = (data, type, agentId = "", currentMode = "", disableTimeAn
|
|
|
348
348
|
userType: "bot",
|
|
349
349
|
userName: userName,
|
|
350
350
|
bodyText: data?.response,
|
|
351
|
-
headerTitle:
|
|
351
|
+
headerTitle: "",
|
|
352
352
|
thinkingResponse: data?.thinkingResponse,
|
|
353
|
-
noShowHeaderTitle:
|
|
353
|
+
noShowHeaderTitle: true,
|
|
354
354
|
bodyType: "text",
|
|
355
355
|
};
|
|
356
356
|
case "stream":
|
|
@@ -614,7 +614,8 @@ const parseResponse = (data, type, agentId = "", currentMode = "", disableTimeAn
|
|
|
614
614
|
timeStamp: timeString,
|
|
615
615
|
userType: "bot",
|
|
616
616
|
userName: userName,
|
|
617
|
-
headerTitle:
|
|
617
|
+
headerTitle: "",
|
|
618
|
+
noShowHeaderTitle: true,
|
|
618
619
|
bodyType: "image",
|
|
619
620
|
bodyText: data?.image || data,
|
|
620
621
|
};
|
|
@@ -1119,6 +1120,66 @@ const getFormattedApplicationName = (applicationURL) => {
|
|
|
1119
1120
|
}
|
|
1120
1121
|
};
|
|
1121
1122
|
|
|
1123
|
+
/**
|
|
1124
|
+
* Resolves a link href to an in-app route (path + search + hash) when the link
|
|
1125
|
+
* points to a screen of this application, otherwise returns null.
|
|
1126
|
+
* Handles both relative links ("/inventory-smart/create-allocation?step=0") and
|
|
1127
|
+
* absolute links sent by the backend
|
|
1128
|
+
* ("https://tapestry.test.impactsmartsuite.com/inventory-smart/create-allocation?step=0").
|
|
1129
|
+
*/
|
|
1130
|
+
const resolveInternalPath = (href) => {
|
|
1131
|
+
if (!href || typeof href !== 'string')
|
|
1132
|
+
return null;
|
|
1133
|
+
// Non navigational protocols (mailto:, tel:, javascript:, #anchor) stay as-is
|
|
1134
|
+
if (/^(mailto:|tel:|javascript:)/i.test(href) || href.startsWith('#'))
|
|
1135
|
+
return null;
|
|
1136
|
+
try {
|
|
1137
|
+
const url = new URL(href, window.location.origin);
|
|
1138
|
+
if (url.protocol !== 'http:' && url.protocol !== 'https:')
|
|
1139
|
+
return null;
|
|
1140
|
+
const currentApp = window.location.pathname.split('/')[1];
|
|
1141
|
+
const targetApp = url.pathname.split('/')[1];
|
|
1142
|
+
// Same origin, or a different host of the same app (e.g. backend returns the
|
|
1143
|
+
// deployed host while running locally) - both resolve to a client side route
|
|
1144
|
+
const isInternal = url.origin === window.location.origin ||
|
|
1145
|
+
(!!currentApp && currentApp === targetApp);
|
|
1146
|
+
if (!isInternal)
|
|
1147
|
+
return null;
|
|
1148
|
+
return `${url.pathname}${url.search}${url.hash}`;
|
|
1149
|
+
}
|
|
1150
|
+
catch (e) {
|
|
1151
|
+
return null;
|
|
1152
|
+
}
|
|
1153
|
+
};
|
|
1154
|
+
/**
|
|
1155
|
+
* Minimizes the chat window so the user can see the screen they navigated to.
|
|
1156
|
+
* SmartBot (index.tsx) listens for this event and sets partialClose.
|
|
1157
|
+
*/
|
|
1158
|
+
const minimizeChatBot = () => {
|
|
1159
|
+
window.dispatchEvent(new CustomEvent("smartBotMinimize"));
|
|
1160
|
+
};
|
|
1161
|
+
/**
|
|
1162
|
+
* Anchor rendered inside chatbot markdown. Internal links are navigated through
|
|
1163
|
+
* react-router so the chatbot is not remounted by a full page load.
|
|
1164
|
+
*/
|
|
1165
|
+
const MarkdownLink = ({ href, children, ...props }) => {
|
|
1166
|
+
const navigate = reactRouterDomV5Compat.useNavigate();
|
|
1167
|
+
const handleClick = (event) => {
|
|
1168
|
+
// Let the browser handle new tab / new window / download intents
|
|
1169
|
+
if (event.metaKey || event.ctrlKey || event.shiftKey || event.altKey || event.button !== 0)
|
|
1170
|
+
return;
|
|
1171
|
+
const internalPath = resolveInternalPath(href);
|
|
1172
|
+
if (!internalPath)
|
|
1173
|
+
return;
|
|
1174
|
+
event.preventDefault();
|
|
1175
|
+
const currentPath = `${window.location.pathname}${window.location.search}`;
|
|
1176
|
+
if (currentPath !== internalPath) {
|
|
1177
|
+
navigate(internalPath);
|
|
1178
|
+
}
|
|
1179
|
+
minimizeChatBot();
|
|
1180
|
+
};
|
|
1181
|
+
return (jsxRuntime.jsx("a", { href: href, target: "_self", onClick: handleClick, ...props, children: children }));
|
|
1182
|
+
};
|
|
1122
1183
|
/**
|
|
1123
1184
|
* Checks whether the input string contains meaningful HTML markup
|
|
1124
1185
|
* (beyond simple inline tags like <b>, <i>, <em>, <strong>, <br>, <a>, <u>
|
|
@@ -1159,9 +1220,16 @@ const preprocessMarkdown = (content) => {
|
|
|
1159
1220
|
.replace(/(^|\n)([^\n-•]*[a-zA-Z0-9][^\n]*)\n([-•]\s+)/g, '$1$2\n\n$3')
|
|
1160
1221
|
// Handle list items with - or • appearing directly after text without newline
|
|
1161
1222
|
// Only treat as a new bullet when preceded by sentence-ending punctuation (to avoid splitting inline hyphens like "KSO- ORLANDO")
|
|
1162
|
-
|
|
1163
|
-
//
|
|
1164
|
-
.replace(/(\n
|
|
1223
|
+
// [^\S\n] (horizontal whitespace only) keeps this from crossing line breaks,
|
|
1224
|
+
// which would dedent already correctly indented nested bullets
|
|
1225
|
+
.replace(/([.!?:)"])[^\S\n]*([-\u2022])[^\S\n]+/g, '$1\n\n$2 ')
|
|
1226
|
+
// Handle nested list items with proper indentation.
|
|
1227
|
+
// Matching only horizontal whitespace after the newline keeps blank lines and
|
|
1228
|
+
// top level numbered items intact (indenting those turns them into plain text).
|
|
1229
|
+
// Normalize to 3 spaces: enough to nest under both "- " and "1. " parents, and
|
|
1230
|
+
// below the 4 space threshold that would turn the line into a code block.
|
|
1231
|
+
// Indents of 4 or more are left untouched (deliberate deeper nesting).
|
|
1232
|
+
.replace(/(\n[^\S\n]{2,3})([-\u2022]|\d+\.)[^\S\n]+/g, '\n $2 ')
|
|
1165
1233
|
// Ensure double line breaks after list sections
|
|
1166
1234
|
.replace(/(\n\d+\.\s+.*?)(\n\n###)/g, '$1\n$2')
|
|
1167
1235
|
.replace(/(\n[-•]\s+.*?)(\n\n###)/g, '$1\n$2')
|
|
@@ -1173,8 +1241,8 @@ const preprocessMarkdown = (content) => {
|
|
|
1173
1241
|
* Custom components for markdown rendering
|
|
1174
1242
|
*/
|
|
1175
1243
|
const markdownComponents = {
|
|
1176
|
-
// Custom link component that
|
|
1177
|
-
a:
|
|
1244
|
+
// Custom link component that navigates in-app without reloading the page
|
|
1245
|
+
a: MarkdownLink,
|
|
1178
1246
|
// Custom code component
|
|
1179
1247
|
code: ({ children, className, ...props }) => (jsxRuntime.jsx("code", { className: `markdown-code ${className || ''}`, ...props, children: children })),
|
|
1180
1248
|
// Custom pre component for code blocks
|
|
@@ -1194,13 +1262,32 @@ const markdownComponents = {
|
|
|
1194
1262
|
* Markdown renderer component with sanitization
|
|
1195
1263
|
*/
|
|
1196
1264
|
const TextRenderer = ({ text, thinking }) => {
|
|
1265
|
+
const navigate = reactRouterDomV5Compat.useNavigate();
|
|
1266
|
+
// Click delegation for anchors inside raw HTML content (dangerouslySetInnerHTML),
|
|
1267
|
+
// so in-app links navigate through react-router instead of reloading the page.
|
|
1268
|
+
const handleHtmlClick = (event) => {
|
|
1269
|
+
if (event.metaKey || event.ctrlKey || event.shiftKey || event.altKey || event.button !== 0)
|
|
1270
|
+
return;
|
|
1271
|
+
const anchor = event.target.closest?.('a');
|
|
1272
|
+
if (!anchor || anchor.target === '_blank')
|
|
1273
|
+
return;
|
|
1274
|
+
const internalPath = resolveInternalPath(anchor.getAttribute('href'));
|
|
1275
|
+
if (!internalPath)
|
|
1276
|
+
return;
|
|
1277
|
+
event.preventDefault();
|
|
1278
|
+
const currentPath = `${window.location.pathname}${window.location.search}`;
|
|
1279
|
+
if (currentPath !== internalPath) {
|
|
1280
|
+
navigate(internalPath);
|
|
1281
|
+
}
|
|
1282
|
+
minimizeChatBot();
|
|
1283
|
+
};
|
|
1197
1284
|
// If the input contains rich HTML, render it directly with DOMPurify sanitization
|
|
1198
1285
|
if (containsRichHtml(text)) {
|
|
1199
1286
|
const sanitizedHtml = DOMPurify.sanitize(text, {
|
|
1200
1287
|
ADD_TAGS: ['style'],
|
|
1201
1288
|
ADD_ATTR: ['style', 'class', 'target', 'rel'],
|
|
1202
1289
|
});
|
|
1203
|
-
return (jsxRuntime.jsx("div", { className: `markdown-content md-content ${thinking ? "thinking" : ""}`, dangerouslySetInnerHTML: { __html: sanitizedHtml } }));
|
|
1290
|
+
return (jsxRuntime.jsx("div", { className: `markdown-content md-content ${thinking ? "thinking" : ""}`, onClick: handleHtmlClick, dangerouslySetInnerHTML: { __html: sanitizedHtml } }));
|
|
1204
1291
|
}
|
|
1205
1292
|
// Otherwise, use the existing markdown pipeline
|
|
1206
1293
|
const processedContent = preprocessMarkdown(text);
|
|
@@ -5031,7 +5118,7 @@ const ChipsContent = ({ bodyText, props }) => {
|
|
|
5031
5118
|
const classes = useStyles$a();
|
|
5032
5119
|
const globalClasses = globalStyles();
|
|
5033
5120
|
return (jsxRuntime.jsx("div", { className: `${globalClasses.flexRow} ${globalClasses.flexWrap} ${globalClasses.gap} ${globalClasses.verticalAlignCenter}`, children: bodyText.map((data, index) => {
|
|
5034
|
-
const callBack = data.interactable
|
|
5121
|
+
const callBack = data.interactable && props
|
|
5035
5122
|
? Object.entries(props).filter((entry) => entry[0] === data.actionName)?.[0]?.[1]
|
|
5036
5123
|
: null;
|
|
5037
5124
|
return (jsxRuntime.jsx(material.Typography, { component: "span", variant: "body1", className: `${classes.gptChips} ${data.interactable ? globalClasses.cursorPointer : ""}`, onClick: () => {
|
|
@@ -5098,7 +5185,7 @@ const QuestionsContent = ({ bodyText, props }) => {
|
|
|
5098
5185
|
};
|
|
5099
5186
|
};
|
|
5100
5187
|
return (jsxRuntime.jsx("div", { className: `${globalClasses.flexRow} ${globalClasses.flexColumn} ${classes.gptQuestionContainer}`, children: bodyText.map((data, index) => {
|
|
5101
|
-
const callBack = data.interactable
|
|
5188
|
+
const callBack = data.interactable && props
|
|
5102
5189
|
? Object.entries(props).filter((entry) => entry[0] === data.actionName)?.[0]?.[1]
|
|
5103
5190
|
: null;
|
|
5104
5191
|
return (jsxRuntime.jsxs("div", { className: `${globalClasses.layoutAlignStart} ${classes.gptQuestionBlock}`, style: {
|
|
@@ -6849,6 +6936,36 @@ const fetchCrossFilterOptions = async (filterConfig, existingSelections = [], al
|
|
|
6849
6936
|
}
|
|
6850
6937
|
};
|
|
6851
6938
|
|
|
6939
|
+
const useStyles$6 = styles.makeStyles(() => ({
|
|
6940
|
+
htmlContentContainer: {
|
|
6941
|
+
width: "100%",
|
|
6942
|
+
"& *": {
|
|
6943
|
+
boxSizing: "border-box",
|
|
6944
|
+
},
|
|
6945
|
+
},
|
|
6946
|
+
}));
|
|
6947
|
+
const HtmlContent = ({ bodyText }) => {
|
|
6948
|
+
const classes = useStyles$6();
|
|
6949
|
+
const containerRef = React.useRef(null);
|
|
6950
|
+
const content = bodyText?.content || "";
|
|
6951
|
+
React.useEffect(() => {
|
|
6952
|
+
if (containerRef.current && content) {
|
|
6953
|
+
const sanitizedHtml = DOMPurify.sanitize(content, {
|
|
6954
|
+
ADD_TAGS: ["style", "details", "summary"],
|
|
6955
|
+
ADD_ATTR: ["open", "target", "rel", "class", "style"],
|
|
6956
|
+
ALLOW_DATA_ATTR: true,
|
|
6957
|
+
FORCE_BODY: true,
|
|
6958
|
+
WHOLE_DOCUMENT: false,
|
|
6959
|
+
});
|
|
6960
|
+
containerRef.current.innerHTML = sanitizedHtml;
|
|
6961
|
+
}
|
|
6962
|
+
}, [content]);
|
|
6963
|
+
if (!content) {
|
|
6964
|
+
return null;
|
|
6965
|
+
}
|
|
6966
|
+
return (jsxRuntime.jsx("div", { ref: containerRef, className: classes.htmlContentContainer }));
|
|
6967
|
+
};
|
|
6968
|
+
|
|
6852
6969
|
const SliderContent = ({ bodyText, isFormDisabled = false, messageIndex }) => {
|
|
6853
6970
|
const formKey = `${messageIndex}_${bodyText?.paramName}`;
|
|
6854
6971
|
const { header, headerOrentiation, inputPosition, label, max, min, required, disabled, } = bodyText;
|
|
@@ -7394,8 +7511,9 @@ const STEP_FORM_TIMEOUT_KEY = "__stepFormTimedOut";
|
|
|
7394
7511
|
* @param {Array} props.formData - Array of raw widget_data items from step_form chunk
|
|
7395
7512
|
* @param {number} props.messageIndex - Index for form state persistence keys
|
|
7396
7513
|
*/
|
|
7397
|
-
const StepFormContent = ({ formData, messageIndex = 0, isFormDisabled = false, showSavedFilters = true, preSelectedFilters = null }) => {
|
|
7514
|
+
const StepFormContent = ({ formData, messageIndex = 0, isFormDisabled = false, showSavedFilters = true, preSelectedFilters = null, botProps = null, currentMode = "", agentId = "", sessionId = "", }) => {
|
|
7398
7515
|
const dispatch = reactRedux.useDispatch();
|
|
7516
|
+
const classes = useStyles$a();
|
|
7399
7517
|
const savedFilterSets = reactRedux.useSelector((state) => state.smartBotReducer.savedFilterSets);
|
|
7400
7518
|
const persistedFormValues = reactRedux.useSelector((state) => state.smartBotReducer.persistedFormValues);
|
|
7401
7519
|
const chatbotContext = reactRedux.useSelector((state) => state.smartBotReducer.chatbotContext);
|
|
@@ -7668,7 +7786,11 @@ const StepFormContent = ({ formData, messageIndex = 0, isFormDisabled = false, s
|
|
|
7668
7786
|
case "text":
|
|
7669
7787
|
return jsxRuntime.jsx(TextContent, { bodyText: parsedData.bodyText, botData: parsedData }, key);
|
|
7670
7788
|
case "chips":
|
|
7671
|
-
return jsxRuntime.jsx(
|
|
7789
|
+
return parsedData.isMultiSelect ? (jsxRuntime.jsx(SelectableChips, { bodyText: parsedData.bodyText, chipType: "selectable", utilityData: parsedData.utilityData, props: botProps }, key)) : (jsxRuntime.jsx(ChipsContent, { bodyText: parsedData.bodyText, props: botProps }, key));
|
|
7790
|
+
case "questions":
|
|
7791
|
+
return jsxRuntime.jsx(QuestionsContent, { bodyText: parsedData.bodyText, props: botProps }, key);
|
|
7792
|
+
case "html":
|
|
7793
|
+
return jsxRuntime.jsx(HtmlContent, { bodyText: parsedData.bodyText }, key);
|
|
7672
7794
|
case "table":
|
|
7673
7795
|
return jsxRuntime.jsx(TableContent, { bodyText: parsedData.bodyText }, key);
|
|
7674
7796
|
case "graph":
|
|
@@ -7699,12 +7821,18 @@ const StepFormContent = ({ formData, messageIndex = 0, isFormDisabled = false, s
|
|
|
7699
7821
|
const buttonItems = [];
|
|
7700
7822
|
formData.forEach((item, index) => {
|
|
7701
7823
|
try {
|
|
7702
|
-
const parsedData = parseResponse(item, item.type,
|
|
7824
|
+
const parsedData = parseResponse(item, item.type, agentId, currentMode, true, sessionId);
|
|
7703
7825
|
if (!parsedData)
|
|
7704
7826
|
return;
|
|
7705
|
-
const
|
|
7706
|
-
if (!
|
|
7827
|
+
const body = renderItem(parsedData, index);
|
|
7828
|
+
if (!body)
|
|
7707
7829
|
return;
|
|
7830
|
+
// Skip the block header when it is just a repeat of the label the widget
|
|
7831
|
+
// renders itself (parseResponse derives headerTitle from label for inputs).
|
|
7832
|
+
const showHeaderTitle = !parsedData?.noShowHeaderTitle &&
|
|
7833
|
+
Boolean(parsedData?.headerTitle?.length) &&
|
|
7834
|
+
parsedData.headerTitle !== parsedData?.bodyText?.label;
|
|
7835
|
+
const rendered = showHeaderTitle ? (jsxRuntime.jsxs(React.Fragment, { children: [jsxRuntime.jsx("div", { className: `${classes.chatbotText} ${classes.boldText} ${classes.combinedBlockHeaderTitle}`, children: parsedData.headerTitle }), body] }, `step-form-block-${index}`)) : (body);
|
|
7708
7836
|
if (parsedData.bodyType === "button") {
|
|
7709
7837
|
buttonItems.push(rendered);
|
|
7710
7838
|
}
|
|
@@ -7727,7 +7855,7 @@ const resetStepFormTimeoutFlag = () => {
|
|
|
7727
7855
|
sessionStorage.removeItem(STEP_FORM_TIMEOUT_KEY);
|
|
7728
7856
|
};
|
|
7729
7857
|
|
|
7730
|
-
const useStyles$
|
|
7858
|
+
const useStyles$5 = styles.makeStyles(() => ({
|
|
7731
7859
|
subStepMarkdown: {
|
|
7732
7860
|
// Inherit font styles from parent (.progressSubItem)
|
|
7733
7861
|
fontFamily: 'inherit',
|
|
@@ -7801,14 +7929,14 @@ const preprocessSubStepMarkdown = (content) => {
|
|
|
7801
7929
|
.trim();
|
|
7802
7930
|
};
|
|
7803
7931
|
const SubStepRenderer = ({ text }) => {
|
|
7804
|
-
const classes = useStyles$
|
|
7932
|
+
const classes = useStyles$5();
|
|
7805
7933
|
if (!text)
|
|
7806
7934
|
return null;
|
|
7807
7935
|
const processed = preprocessSubStepMarkdown(text);
|
|
7808
7936
|
return (jsxRuntime.jsx("div", { className: classes.subStepMarkdown, children: jsxRuntime.jsx(ReactMarkdown, { remarkPlugins: [remarkGfm, remarkBreaks], children: processed }) }));
|
|
7809
7937
|
};
|
|
7810
7938
|
|
|
7811
|
-
const useStyles$
|
|
7939
|
+
const useStyles$4 = makeStyles((theme) => ({
|
|
7812
7940
|
"@global": {
|
|
7813
7941
|
"@keyframes progressDotPulse": {
|
|
7814
7942
|
"0%": {
|
|
@@ -8082,7 +8210,7 @@ const getQuestionStatus$1 = (questionSteps) => {
|
|
|
8082
8210
|
/**
|
|
8083
8211
|
* Renders a single progress bar item (main point + sub-items)
|
|
8084
8212
|
*/
|
|
8085
|
-
const ProgressBarItem$1 = ({ question, questionSteps, isLast, classes, formData, showSavedFilters = true, preSelectedFilters = null, isFormDisabled, onAllSubItemsAnimated = undefined }) => {
|
|
8213
|
+
const ProgressBarItem$1 = ({ question, questionSteps, isLast, classes, formData, showSavedFilters = true, preSelectedFilters = null, isFormDisabled, onAllSubItemsAnimated = undefined, botProps = null, currentMode = "", agentId = "", sessionId = "" }) => {
|
|
8086
8214
|
const status = getQuestionStatus$1(questionSteps);
|
|
8087
8215
|
const animatedCountRef = React.useRef(0);
|
|
8088
8216
|
const [isExpanded, setIsExpanded] = React.useState(true);
|
|
@@ -8116,10 +8244,10 @@ const ProgressBarItem$1 = ({ question, questionSteps, isLast, classes, formData,
|
|
|
8116
8244
|
if (animatedCountRef.current >= arr.length && onAllSubItemsAnimated) {
|
|
8117
8245
|
onAllSubItemsAnimated();
|
|
8118
8246
|
}
|
|
8119
|
-
} }) }, idx))) })), formData && isExpanded && (jsxRuntime.jsx("div", { className: classes.stepFormContainer, children: jsxRuntime.jsx(StepFormContent, { formData: formData, isFormDisabled: isFormDisabled, showSavedFilters: showSavedFilters, preSelectedFilters: preSelectedFilters }) }))] })] }));
|
|
8247
|
+
} }) }, idx))) })), formData && isExpanded && (jsxRuntime.jsx("div", { className: classes.stepFormContainer, children: jsxRuntime.jsx(StepFormContent, { formData: formData, isFormDisabled: isFormDisabled, showSavedFilters: showSavedFilters, preSelectedFilters: preSelectedFilters, botProps: botProps, currentMode: currentMode, agentId: agentId, sessionId: sessionId }) }))] })] }));
|
|
8120
8248
|
};
|
|
8121
|
-
const Steps$1 = ({ steps, setSteps, done, setTabValue, setDone, finalStepDone, setFinalStepDone, stepChange, currentMode, questions = [], questionsStepsMap = {}, stepFormDataMap = {}, isFormDisabled = false, }) => {
|
|
8122
|
-
const classes = useStyles$
|
|
8249
|
+
const Steps$1 = ({ steps, setSteps, done, setTabValue, setDone, finalStepDone, setFinalStepDone, stepChange, currentMode, questions = [], questionsStepsMap = {}, stepFormDataMap = {}, isFormDisabled = false, botProps = null, agentId = "", sessionId = "", }) => {
|
|
8250
|
+
const classes = useStyles$4();
|
|
8123
8251
|
React.useState(false);
|
|
8124
8252
|
const [showThinking, setShowThinking] = React.useState(false);
|
|
8125
8253
|
// Determine if last question is fully completed (all sub-steps done)
|
|
@@ -8201,7 +8329,7 @@ const Steps$1 = ({ steps, setSteps, done, setTabValue, setDone, finalStepDone, s
|
|
|
8201
8329
|
const showSavedFilters = formEntry && !Array.isArray(formEntry) ? formEntry.showSavedFilters : true;
|
|
8202
8330
|
const preSelectedFilters = formEntry && !Array.isArray(formEntry) ? formEntry.preSelectedFilters : null;
|
|
8203
8331
|
const isLast = index === questions.length - 1;
|
|
8204
|
-
return (jsxRuntime.jsx(ProgressBarItem$1, { question: question, questionSteps: questionSteps, isLast: isLast && !showThinking, classes: classes, formData: formData, isFormDisabled: isFormDisabled, showSavedFilters: showSavedFilters, preSelectedFilters: preSelectedFilters, onAllSubItemsAnimated: isLast && lastQuestionCompleted && !done
|
|
8332
|
+
return (jsxRuntime.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
|
|
8205
8333
|
? () => setShowThinking(true)
|
|
8206
8334
|
: undefined }, index));
|
|
8207
8335
|
}), showThinking && !done && (jsxRuntime.jsx("div", { style: {
|
|
@@ -8209,36 +8337,6 @@ const Steps$1 = ({ steps, setSteps, done, setTabValue, setDone, finalStepDone, s
|
|
|
8209
8337
|
}, children: jsxRuntime.jsx(ProgressBarItem$1, { question: "Thinking", questionSteps: [{ header: "", sub_header: "", step_status: "not-completed" }], isLast: true, classes: classes, formData: null, isFormDisabled: isFormDisabled }) }))] }));
|
|
8210
8338
|
};
|
|
8211
8339
|
|
|
8212
|
-
const useStyles$4 = styles.makeStyles(() => ({
|
|
8213
|
-
htmlContentContainer: {
|
|
8214
|
-
width: "100%",
|
|
8215
|
-
"& *": {
|
|
8216
|
-
boxSizing: "border-box",
|
|
8217
|
-
},
|
|
8218
|
-
},
|
|
8219
|
-
}));
|
|
8220
|
-
const HtmlContent = ({ bodyText }) => {
|
|
8221
|
-
const classes = useStyles$4();
|
|
8222
|
-
const containerRef = React.useRef(null);
|
|
8223
|
-
const content = bodyText?.content || "";
|
|
8224
|
-
React.useEffect(() => {
|
|
8225
|
-
if (containerRef.current && content) {
|
|
8226
|
-
const sanitizedHtml = DOMPurify.sanitize(content, {
|
|
8227
|
-
ADD_TAGS: ["style", "details", "summary"],
|
|
8228
|
-
ADD_ATTR: ["open", "target", "rel", "class", "style"],
|
|
8229
|
-
ALLOW_DATA_ATTR: true,
|
|
8230
|
-
FORCE_BODY: true,
|
|
8231
|
-
WHOLE_DOCUMENT: false,
|
|
8232
|
-
});
|
|
8233
|
-
containerRef.current.innerHTML = sanitizedHtml;
|
|
8234
|
-
}
|
|
8235
|
-
}, [content]);
|
|
8236
|
-
if (!content) {
|
|
8237
|
-
return null;
|
|
8238
|
-
}
|
|
8239
|
-
return (jsxRuntime.jsx("div", { ref: containerRef, className: classes.htmlContentContainer }));
|
|
8240
|
-
};
|
|
8241
|
-
|
|
8242
8340
|
const renderWidgetItem = (item, index, isFormDisabled) => {
|
|
8243
8341
|
try {
|
|
8244
8342
|
const parsedData = parseResponse(item, item.type, "", "", true);
|
|
@@ -8290,7 +8388,7 @@ const AgentResponse$1 = (props) => {
|
|
|
8290
8388
|
};
|
|
8291
8389
|
|
|
8292
8390
|
const StepsResponseTab = (props) => {
|
|
8293
|
-
const { steps, setSteps, stepsDone, setStepsDone, finalStepDone, setFinalStepDone, content, isStreaming, stepChange, currentMode, questions, questionsStepsMap, stepFormDataMap, isFormDisabled, streamingWidgetData, isRetrying, } = props;
|
|
8391
|
+
const { steps, setSteps, stepsDone, setStepsDone, finalStepDone, setFinalStepDone, content, isStreaming, stepChange, currentMode, questions, questionsStepsMap, stepFormDataMap, isFormDisabled, streamingWidgetData, isRetrying, botProps, agentId, sessionId, } = props;
|
|
8294
8392
|
const dispatch = reactRedux.useDispatch();
|
|
8295
8393
|
const thinkingContext = reactRedux.useSelector((state) => state.smartBotReducer.thinkingContext);
|
|
8296
8394
|
const streamStartTimeRef = React.useRef(thinkingContext?.streamStartTime);
|
|
@@ -8354,7 +8452,7 @@ const StepsResponseTab = (props) => {
|
|
|
8354
8452
|
icon: jsxRuntime.jsx(PsychologyOutlinedIcon, { fontSize: "large" }),
|
|
8355
8453
|
},
|
|
8356
8454
|
], tabPanels: [
|
|
8357
|
-
jsxRuntime.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 }),
|
|
8455
|
+
jsxRuntime.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 }),
|
|
8358
8456
|
jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(AgentResponse$1, { content: content, isStreaming: isStreaming, streamingWidgetData: streamingWidgetData, isFormDisabled: isFormDisabled || isTimedOut }), timeoutMessage && (jsxRuntime.jsx("div", { style: { marginTop: "8px", padding: "0 8px" }, children: jsxRuntime.jsx(TextRenderer, { text: timeoutMessage, thinking: "" }) }))] }),
|
|
8359
8457
|
], value: tabValue }) }));
|
|
8360
8458
|
};
|
|
@@ -8536,7 +8634,7 @@ const streamStateMap = new Map();
|
|
|
8536
8634
|
* @param {React.RefObject} botData.utilityObject.chatBodyRef - Ref to chat body element
|
|
8537
8635
|
* @param {Function} botData.utilityObject.setChatDataState - Function to update chat data state
|
|
8538
8636
|
*/
|
|
8539
|
-
const StreamedContent = ({ botData }) => {
|
|
8637
|
+
const StreamedContent = ({ botData, botProps }) => {
|
|
8540
8638
|
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 || {};
|
|
8541
8639
|
const classes = useStyles$7();
|
|
8542
8640
|
useStyles$a();
|
|
@@ -9715,8 +9813,13 @@ const StreamedContent = ({ botData }) => {
|
|
|
9715
9813
|
}, 1000);
|
|
9716
9814
|
}
|
|
9717
9815
|
}, [isStreamingDone, thinkingTime, activeConversationId]);
|
|
9816
|
+
// Show/hide the stop (cancel execution) icon while the stream is active.
|
|
9817
|
+
// Gate on state only - sourceRef is a ref, so mutating it never re-runs this
|
|
9818
|
+
// effect. Relying on it meant that if the source wasn't assigned yet on the
|
|
9819
|
+
// first run, isStop was set to false and never re-evaluated for the rest of
|
|
9820
|
+
// the stream, leaving the cancel button hidden.
|
|
9718
9821
|
React.useEffect(() => {
|
|
9719
|
-
if (
|
|
9822
|
+
if (isStreaming && !isStreamingDone) {
|
|
9720
9823
|
setIsStop(true);
|
|
9721
9824
|
setFunctionsState({
|
|
9722
9825
|
...functionsState,
|
|
@@ -9727,7 +9830,7 @@ const StreamedContent = ({ botData }) => {
|
|
|
9727
9830
|
else {
|
|
9728
9831
|
setIsStop(false);
|
|
9729
9832
|
}
|
|
9730
|
-
}, [isStreaming]);
|
|
9833
|
+
}, [isStreaming, isStreamingDone]);
|
|
9731
9834
|
/**
|
|
9732
9835
|
* Aborts the current streaming connection
|
|
9733
9836
|
*/
|
|
@@ -9740,10 +9843,12 @@ const StreamedContent = ({ botData }) => {
|
|
|
9740
9843
|
setRetryCountdown(0);
|
|
9741
9844
|
}
|
|
9742
9845
|
retryCountRef.current = MAX_RETRY_COUNT; // Exhaust retries so no further auto-retries happen
|
|
9743
|
-
if (
|
|
9846
|
+
if (isStreaming) {
|
|
9744
9847
|
setWasStreamingAborted(true);
|
|
9745
9848
|
wasStreamingAbortedRef.current = true;
|
|
9746
|
-
sourceRef.current
|
|
9849
|
+
if (sourceRef.current) {
|
|
9850
|
+
sourceRef.current.close();
|
|
9851
|
+
}
|
|
9747
9852
|
setIsStreaming(false);
|
|
9748
9853
|
setIsStreamingDone(true);
|
|
9749
9854
|
// Mark as completed+aborted so tab-switch remounts don't restart the stream.
|
|
@@ -9903,7 +10008,7 @@ const StreamedContent = ({ botData }) => {
|
|
|
9903
10008
|
* @returns {JSX.Element} Rendered content with optional blinking cursor
|
|
9904
10009
|
*/
|
|
9905
10010
|
const renderContent = () => {
|
|
9906
|
-
return (jsxRuntime.jsxs("div", { className: classes.streamContainer, children: [jsxRuntime.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 && (jsxRuntime.jsx("div", { className: classes.retryContainer, children: jsxRuntime.jsx(TextRenderer, { text: `Auto re-trying in ${retryCountdown}s`, thinking: "" }) }))] }));
|
|
10011
|
+
return (jsxRuntime.jsxs("div", { className: classes.streamContainer, children: [jsxRuntime.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 && (jsxRuntime.jsx("div", { className: classes.retryContainer, children: jsxRuntime.jsx(TextRenderer, { text: `Auto re-trying in ${retryCountdown}s`, thinking: "" }) }))] }));
|
|
9907
10012
|
};
|
|
9908
10013
|
if (currentMode === "agent") {
|
|
9909
10014
|
return renderContent();
|
|
@@ -10173,8 +10278,9 @@ const AgentResponse = ({ children }) => {
|
|
|
10173
10278
|
// Only the active instance should process stepFormStreamData from Redux.
|
|
10174
10279
|
let instanceCounter = 0;
|
|
10175
10280
|
let activeTabularInstanceId = null;
|
|
10176
|
-
const TabularContent = ({ steps: initialSteps, currentTabValue, children, questions: initialQuestions = [], questionsStepsMap: initialQuestionsStepsMap = {}, stepFormDataMap: initialStepFormDataMap = {}, isFormDisabled = false, sessionId: propSessionId = "" }) => {
|
|
10281
|
+
const TabularContent = ({ steps: initialSteps, currentTabValue, children, questions: initialQuestions = [], questionsStepsMap: initialQuestionsStepsMap = {}, stepFormDataMap: initialStepFormDataMap = {}, isFormDisabled = false, sessionId: propSessionId = "", botProps = null, currentMode = "", agentId = "" }) => {
|
|
10177
10282
|
const dispatch = reactRedux.useDispatch();
|
|
10283
|
+
const chatClasses = useStyles$a();
|
|
10178
10284
|
const stepFormStreamData = reactRedux.useSelector((state) => state.smartBotReducer.stepFormStreamData);
|
|
10179
10285
|
const thinkingContext = reactRedux.useSelector((state) => state.smartBotReducer.thinkingContext);
|
|
10180
10286
|
const streamStartTimeRef = React.useRef(thinkingContext?.streamStartTime);
|
|
@@ -10258,40 +10364,55 @@ const TabularContent = ({ steps: initialSteps, currentTabValue, children, questi
|
|
|
10258
10364
|
};
|
|
10259
10365
|
}, []);
|
|
10260
10366
|
// Render a widget item from SSE data
|
|
10367
|
+
const renderWidgetBody = (parsedData, key) => {
|
|
10368
|
+
switch (parsedData.bodyType) {
|
|
10369
|
+
case "text":
|
|
10370
|
+
return jsxRuntime.jsx(TextContent, { bodyText: parsedData.bodyText, botData: parsedData }, key);
|
|
10371
|
+
case "chips":
|
|
10372
|
+
return parsedData.isMultiSelect ? (jsxRuntime.jsx(SelectableChips, { bodyText: parsedData.bodyText, chipType: "selectable", utilityData: parsedData.utilityData, props: botProps }, key)) : (jsxRuntime.jsx(ChipsContent, { bodyText: parsedData.bodyText, props: botProps }, key));
|
|
10373
|
+
case "questions":
|
|
10374
|
+
return jsxRuntime.jsx(QuestionsContent, { bodyText: parsedData.bodyText, props: botProps }, key);
|
|
10375
|
+
case "image":
|
|
10376
|
+
return jsxRuntime.jsx(ImageContent, { bodyText: parsedData.bodyText }, key);
|
|
10377
|
+
case "table":
|
|
10378
|
+
return jsxRuntime.jsx(TableContent, { bodyText: parsedData.bodyText }, key);
|
|
10379
|
+
case "graph":
|
|
10380
|
+
return jsxRuntime.jsx(GraphContent, { bodyText: parsedData.bodyText }, key);
|
|
10381
|
+
case "radio":
|
|
10382
|
+
return jsxRuntime.jsx(RadioContent, { bodyText: parsedData.bodyText, isFormDisabled: isFormDisabled }, key);
|
|
10383
|
+
case "checkbox":
|
|
10384
|
+
return jsxRuntime.jsx(CheckboxContent, { bodyText: parsedData.bodyText, isFormDisabled: isFormDisabled }, key);
|
|
10385
|
+
case "select":
|
|
10386
|
+
return jsxRuntime.jsx(SelectContent, { bodyText: parsedData.bodyText, isFormDisabled: isFormDisabled }, key);
|
|
10387
|
+
case "slider":
|
|
10388
|
+
return jsxRuntime.jsx(SliderContent, { bodyText: parsedData.bodyText, isFormDisabled: isFormDisabled }, key);
|
|
10389
|
+
case "button":
|
|
10390
|
+
return jsxRuntime.jsx(ButtonContent, { bodyText: parsedData.bodyText, isFormDisabled: isFormDisabled }, key);
|
|
10391
|
+
case "input":
|
|
10392
|
+
return jsxRuntime.jsx(InputContent, { bodyText: parsedData.bodyText, isFormDisabled: isFormDisabled }, key);
|
|
10393
|
+
case "datePicker":
|
|
10394
|
+
return jsxRuntime.jsx(DatePickerContent, { bodyText: parsedData.bodyText, isFormDisabled: isFormDisabled }, key);
|
|
10395
|
+
case "dateRangePicker":
|
|
10396
|
+
return jsxRuntime.jsx(DateRangePickerContent, { bodyText: parsedData.bodyText, isFormDisabled: isFormDisabled }, key);
|
|
10397
|
+
case "html":
|
|
10398
|
+
return jsxRuntime.jsx(HtmlContent, { bodyText: parsedData.bodyText }, key);
|
|
10399
|
+
default:
|
|
10400
|
+
return null;
|
|
10401
|
+
}
|
|
10402
|
+
};
|
|
10261
10403
|
const renderWidget = (item, index) => {
|
|
10262
10404
|
try {
|
|
10263
|
-
const parsedData = parseResponse(item, item.type,
|
|
10405
|
+
const parsedData = parseResponse(item, item.type, agentId, currentMode, true, propSessionId);
|
|
10264
10406
|
if (!parsedData)
|
|
10265
10407
|
return null;
|
|
10266
10408
|
const key = `restream-widget-${index}`;
|
|
10267
|
-
|
|
10268
|
-
|
|
10269
|
-
|
|
10270
|
-
|
|
10271
|
-
|
|
10272
|
-
|
|
10273
|
-
|
|
10274
|
-
case "radio":
|
|
10275
|
-
return jsxRuntime.jsx(RadioContent, { bodyText: parsedData.bodyText, isFormDisabled: isFormDisabled }, key);
|
|
10276
|
-
case "checkbox":
|
|
10277
|
-
return jsxRuntime.jsx(CheckboxContent, { bodyText: parsedData.bodyText, isFormDisabled: isFormDisabled }, key);
|
|
10278
|
-
case "select":
|
|
10279
|
-
return jsxRuntime.jsx(SelectContent, { bodyText: parsedData.bodyText, isFormDisabled: isFormDisabled }, key);
|
|
10280
|
-
case "slider":
|
|
10281
|
-
return jsxRuntime.jsx(SliderContent, { bodyText: parsedData.bodyText, isFormDisabled: isFormDisabled }, key);
|
|
10282
|
-
case "button":
|
|
10283
|
-
return jsxRuntime.jsx(ButtonContent, { bodyText: parsedData.bodyText, isFormDisabled: isFormDisabled }, key);
|
|
10284
|
-
case "input":
|
|
10285
|
-
return jsxRuntime.jsx(InputContent, { bodyText: parsedData.bodyText, isFormDisabled: isFormDisabled }, key);
|
|
10286
|
-
case "datePicker":
|
|
10287
|
-
return jsxRuntime.jsx(DatePickerContent, { bodyText: parsedData.bodyText, isFormDisabled: isFormDisabled }, key);
|
|
10288
|
-
case "dateRangePicker":
|
|
10289
|
-
return jsxRuntime.jsx(DateRangePickerContent, { bodyText: parsedData.bodyText, isFormDisabled: isFormDisabled }, key);
|
|
10290
|
-
case "html":
|
|
10291
|
-
return jsxRuntime.jsx(HtmlContent, { bodyText: parsedData.bodyText }, key);
|
|
10292
|
-
default:
|
|
10293
|
-
return null;
|
|
10294
|
-
}
|
|
10409
|
+
const body = renderWidgetBody(parsedData, key);
|
|
10410
|
+
if (!body)
|
|
10411
|
+
return null;
|
|
10412
|
+
const showHeaderTitle = !parsedData?.noShowHeaderTitle && Boolean(parsedData?.headerTitle?.length);
|
|
10413
|
+
if (!showHeaderTitle)
|
|
10414
|
+
return body;
|
|
10415
|
+
return (jsxRuntime.jsxs(React.Fragment, { children: [jsxRuntime.jsx("div", { className: `${chatClasses.chatbotText} ${chatClasses.boldText} ${chatClasses.combinedBlockHeaderTitle}`, children: parsedData.headerTitle }), body] }, `restream-widget-block-${index}`));
|
|
10295
10416
|
}
|
|
10296
10417
|
catch (e) {
|
|
10297
10418
|
console.error("[TabularContent] renderWidget error:", e);
|
|
@@ -10661,11 +10782,8 @@ const CombinedContent = ({ botData, props }) => {
|
|
|
10661
10782
|
// Get the array of content items from bodyText
|
|
10662
10783
|
const contentItems = Array.isArray(botData.bodyText) ? botData.bodyText : [];
|
|
10663
10784
|
// Renders the optional block-level header title above a content item.
|
|
10664
|
-
// Text blocks are skipped because their heading is the echoed user query
|
|
10665
|
-
// (response_heading), which we don't want to duplicate in the response.
|
|
10666
10785
|
const renderHeaderTitle = (parsedData) => {
|
|
10667
|
-
const showHeaderTitle = parsedData?.
|
|
10668
|
-
!parsedData?.noShowHeaderTitle &&
|
|
10786
|
+
const showHeaderTitle = !parsedData?.noShowHeaderTitle &&
|
|
10669
10787
|
Boolean(parsedData?.headerTitle?.length);
|
|
10670
10788
|
if (!showHeaderTitle)
|
|
10671
10789
|
return null;
|
|
@@ -10735,7 +10853,7 @@ const CombinedContent = ({ botData, props }) => {
|
|
|
10735
10853
|
const validContent = renderedContent.filter(content => content !== null);
|
|
10736
10854
|
const renderCombinedContent = () => (jsxRuntime.jsx("div", { className: "combined-content-container", children: validContent.length > 0 ? (validContent.map((content, index) => (jsxRuntime.jsx("div", { className: "combined-content-item", children: content }, `wrapper-${index}`)))) : (jsxRuntime.jsx("div", { children: "No valid content to display" })) }));
|
|
10737
10855
|
if (isTabEnabled) {
|
|
10738
|
-
return (jsxRuntime.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() }));
|
|
10856
|
+
return (jsxRuntime.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() }));
|
|
10739
10857
|
}
|
|
10740
10858
|
return renderCombinedContent();
|
|
10741
10859
|
};
|
|
@@ -10774,7 +10892,7 @@ const BotMessage = ({ botData, state, handleLikeDislike, props }) => {
|
|
|
10774
10892
|
case "text":
|
|
10775
10893
|
return jsxRuntime.jsx(TextContent, { bodyText: botData.bodyText, botData: botData });
|
|
10776
10894
|
case "stream":
|
|
10777
|
-
return jsxRuntime.jsx(StreamedContent, { botData: botData });
|
|
10895
|
+
return jsxRuntime.jsx(StreamedContent, { botData: botData, botProps: props });
|
|
10778
10896
|
case "chips":
|
|
10779
10897
|
if (botData.isMultiSelect) {
|
|
10780
10898
|
return (jsxRuntime.jsx(SelectableChips, { bodyText: botData.bodyText, utilityData: botData.utilityData, props: props }));
|
|
@@ -15021,13 +15139,19 @@ const SmartBot = (props) => {
|
|
|
15021
15139
|
if (newChatId !== undefined)
|
|
15022
15140
|
setUniqueChatId(newChatId);
|
|
15023
15141
|
};
|
|
15142
|
+
// Minimize the chat window when the user follows an in-app link from a bot response
|
|
15143
|
+
const handleMinimizeRequest = () => {
|
|
15144
|
+
setPartialClose(true);
|
|
15145
|
+
};
|
|
15024
15146
|
window.addEventListener("stepFormStreamStart", handleStepFormStreamStart);
|
|
15025
15147
|
window.addEventListener("stepFormStreamEnd", handleStepFormStreamEnd);
|
|
15026
15148
|
window.addEventListener("stepFormInitStateUpdate", handleStepFormInitStateUpdate);
|
|
15149
|
+
window.addEventListener("smartBotMinimize", handleMinimizeRequest);
|
|
15027
15150
|
return () => {
|
|
15028
15151
|
window.removeEventListener("stepFormStreamStart", handleStepFormStreamStart);
|
|
15029
15152
|
window.removeEventListener("stepFormStreamEnd", handleStepFormStreamEnd);
|
|
15030
15153
|
window.removeEventListener("stepFormInitStateUpdate", handleStepFormInitStateUpdate);
|
|
15154
|
+
window.removeEventListener("smartBotMinimize", handleMinimizeRequest);
|
|
15031
15155
|
};
|
|
15032
15156
|
}, []);
|
|
15033
15157
|
const fetchCustomBotConfigurations = async () => {
|
|
@@ -15163,6 +15287,13 @@ const SmartBot = (props) => {
|
|
|
15163
15287
|
// );
|
|
15164
15288
|
// return;
|
|
15165
15289
|
// } else {
|
|
15290
|
+
// The library re-fires the `initialClick` tab's onClick from an
|
|
15291
|
+
// effect whose deps (tabList/menuItems/onChatBotResize) are
|
|
15292
|
+
// recreated on every render. Track the previous tab so we only
|
|
15293
|
+
// reset transient state on a real tab change - otherwise these
|
|
15294
|
+
// spurious re-invocations wipe isStop mid-stream and hide the
|
|
15295
|
+
// cancel execution button.
|
|
15296
|
+
const previousActiveTab = activeTab.current.activeTab;
|
|
15166
15297
|
setShowSavedFilters(false);
|
|
15167
15298
|
const agentConversations = chatDataInfoRef?.current[params?.name?.toLowerCase()]?.conversations;
|
|
15168
15299
|
const firstConversationId = agentConversations ? Object.keys(agentConversations)[0] : undefined;
|
|
@@ -15181,7 +15312,9 @@ const SmartBot = (props) => {
|
|
|
15181
15312
|
localStorage.setItem("currentModeData", params?.name?.toLowerCase());
|
|
15182
15313
|
setNewChatScreen(false);
|
|
15183
15314
|
activeTab.current.activeTab = "agent";
|
|
15184
|
-
|
|
15315
|
+
if (previousActiveTab !== "agent") {
|
|
15316
|
+
setIsStop(false);
|
|
15317
|
+
}
|
|
15185
15318
|
// }
|
|
15186
15319
|
// setConversation([]);
|
|
15187
15320
|
// chatDataInfoRef.current[currentMode] = [];
|
|
@@ -15200,6 +15333,8 @@ const SmartBot = (props) => {
|
|
|
15200
15333
|
// );
|
|
15201
15334
|
// return;
|
|
15202
15335
|
// } else {
|
|
15336
|
+
// Only reset transient state on a real tab change.
|
|
15337
|
+
const previousActiveTab = activeTab.current.activeTab;
|
|
15203
15338
|
setShowSavedFilters(false);
|
|
15204
15339
|
let currentModeValue = params?.name?.toLowerCase();
|
|
15205
15340
|
const modeConversations = chatDataInfoRef?.current[currentModeValue]?.conversations;
|
|
@@ -15223,7 +15358,9 @@ const SmartBot = (props) => {
|
|
|
15223
15358
|
chatDataInfoRef.current = lodash.cloneDeep(parsedData);
|
|
15224
15359
|
}
|
|
15225
15360
|
// setNewChatScreen(true);
|
|
15226
|
-
|
|
15361
|
+
if (previousActiveTab !== "navigation") {
|
|
15362
|
+
setIsStop(false);
|
|
15363
|
+
}
|
|
15227
15364
|
setCurrentMode(params?.name?.toLowerCase());
|
|
15228
15365
|
if (firstConversationId) {
|
|
15229
15366
|
setActiveConversationId(firstConversationId);
|
|
@@ -15292,6 +15429,9 @@ const SmartBot = (props) => {
|
|
|
15292
15429
|
// );
|
|
15293
15430
|
// return;
|
|
15294
15431
|
// } else {
|
|
15432
|
+
// Only reset transient state on a real tab change - the library
|
|
15433
|
+
// re-fires this initialClick handler on every render.
|
|
15434
|
+
const previousActiveTab = activeTab.current.activeTab;
|
|
15295
15435
|
setShowSavedFilters(false);
|
|
15296
15436
|
let currentModeValue = params?.name?.toLowerCase();
|
|
15297
15437
|
const modeConversations = chatDataInfoRef?.current[currentModeValue]?.conversations;
|
|
@@ -15315,7 +15455,9 @@ const SmartBot = (props) => {
|
|
|
15315
15455
|
chatDataInfoRef.current = lodash.cloneDeep(parsedData);
|
|
15316
15456
|
}
|
|
15317
15457
|
// setNewChatScreen(true);
|
|
15318
|
-
|
|
15458
|
+
if (previousActiveTab !== "navigation") {
|
|
15459
|
+
setIsStop(false);
|
|
15460
|
+
}
|
|
15319
15461
|
setCurrentMode(params?.name?.toLowerCase());
|
|
15320
15462
|
if (firstConversationId) {
|
|
15321
15463
|
setActiveConversationId(firstConversationId);
|
|
@@ -15346,6 +15488,9 @@ const SmartBot = (props) => {
|
|
|
15346
15488
|
// );
|
|
15347
15489
|
// return;
|
|
15348
15490
|
// } else {
|
|
15491
|
+
// Only reset transient state on a real tab change - the library
|
|
15492
|
+
// re-fires this initialClick handler on every render.
|
|
15493
|
+
const previousActiveTab = activeTab.current.activeTab;
|
|
15349
15494
|
setShowSavedFilters(false);
|
|
15350
15495
|
let currentModeValue = params?.name?.toLowerCase();
|
|
15351
15496
|
const modeConversations = chatDataInfoRef?.current[currentModeValue]?.conversations;
|
|
@@ -15369,7 +15514,9 @@ const SmartBot = (props) => {
|
|
|
15369
15514
|
chatDataInfoRef.current = lodash.cloneDeep(parsedData);
|
|
15370
15515
|
}
|
|
15371
15516
|
// setNewChatScreen(true);
|
|
15372
|
-
|
|
15517
|
+
if (previousActiveTab !== "navigation") {
|
|
15518
|
+
setIsStop(false);
|
|
15519
|
+
}
|
|
15373
15520
|
setCurrentMode(params?.name?.toLowerCase());
|
|
15374
15521
|
if (firstConversationId) {
|
|
15375
15522
|
setActiveConversationId(firstConversationId);
|