impact-chatbot 2.3.38 → 2.3.40

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/index.esm.js CHANGED
@@ -26,6 +26,7 @@ import { CircularProgress, Typography, Grid } from '@mui/material';
26
26
  import { fetchBaseUrl, replaceSpecialCharacter as replaceSpecialCharacter$1, fetchLegacyAgentScreen } from 'core/Utils/functions/utils';
27
27
  import { Button, Modal, Slider, Select, DatePicker, DateRangePicker, Checkbox, RadioButtonGroup, Input, Tabs, Loader, Tooltip, ChatBotComponent } from 'impact-ui-v3';
28
28
  import isArray$2 from 'lodash/isArray';
29
+ import { stopAgentFlow } from 'core/commonComponents/smartBot/services/chatbot-services';
29
30
  import AgGridComponent from 'core/Utils/agGrid';
30
31
  import agGridColumnFormatter from 'core/Utils/agGrid/column-formatter';
31
32
  import CoreChart from 'core/Utils/core-charts';
@@ -33,7 +34,6 @@ import makeStyles$1 from '@mui/styles/makeStyles';
33
34
  import ChevronRightIcon$1 from '@mui/icons-material/ChevronRight';
34
35
  import FormatListBulletedOutlinedIcon from '@mui/icons-material/FormatListBulletedOutlined';
35
36
  import PsychologyOutlinedIcon from '@mui/icons-material/PsychologyOutlined';
36
- import { stopAgentFlow } from 'core/commonComponents/smartBot/services/chatbot-services';
37
37
  import SaveOutlinedIcon from '@mui/icons-material/SaveOutlined';
38
38
  import RangePicker from 'core/commonComponents/dateRangePicker';
39
39
  import NoFilterSetSavedIcon from 'core/coreAssets/chatbot/noFilterSetSaved.svg';
@@ -5263,6 +5263,17 @@ const AxiosSource = (url, opts, messageToStoreRef) => {
5263
5263
  }
5264
5264
  };
5265
5265
 
5266
+ // Module-level control object for step-form SSE stream.
5267
+ // StreamedContent imports this to show/hide the stop icon during the second init stream.
5268
+ const stepFormStreamControl = {
5269
+ isStreaming: false,
5270
+ abort: null,
5271
+ // Session info — set by StreamedContent when step_form arrives
5272
+ sessionId: "",
5273
+ chatId: "",
5274
+ agentId: "",
5275
+ baseUrl: "",
5276
+ };
5266
5277
  const useStyles$5 = makeStyles((theme) => ({
5267
5278
  buttonContainer: {
5268
5279
  display: 'flex',
@@ -5323,11 +5334,11 @@ const ButtonContent = ({ bodyText, isFormDisabled = false, isStepFormSubmit = fa
5323
5334
  sendButton.click();
5324
5335
  };
5325
5336
  const callInitApiStream = (userInput) => {
5326
- // Get session/chat IDs from localStorage — set by StreamedContent on stream completion
5327
- const sessionId = localStorage.getItem("stepForm_sessionId") || "";
5328
- const chatId = localStorage.getItem("stepForm_chatId") || "";
5329
- const agentId = localStorage.getItem("stepForm_agentId") || "";
5330
- const baseUrl = localStorage.getItem("stepForm_baseUrl") || "";
5337
+ // Prefer module-level values (set synchronously by StreamedContent), fall back to sessionStorage
5338
+ const sessionId = stepFormStreamControl.sessionId || sessionStorage.getItem("stepForm_sessionId") || "";
5339
+ const chatId = stepFormStreamControl.chatId || sessionStorage.getItem("stepForm_chatId") || "";
5340
+ const agentId = stepFormStreamControl.agentId || sessionStorage.getItem("stepForm_agentId") || "";
5341
+ const baseUrl = stepFormStreamControl.baseUrl || sessionStorage.getItem("stepForm_baseUrl") || "";
5331
5342
  const payload = {
5332
5343
  agent_id: agentId,
5333
5344
  session_id: sessionId,
@@ -5341,8 +5352,25 @@ const ButtonContent = ({ bodyText, isFormDisabled = false, isStepFormSubmit = fa
5341
5352
  : `${BASE_API}/core/chatbot/agent/init`;
5342
5353
  // Collect all chunks, dispatch once when stream ends
5343
5354
  const chunksRef = [];
5344
- // Signal that streaming has started
5355
+ // Expose stream control BEFORE Redux dispatch so SmartBot index.jsx can show stop icon
5356
+ stepFormStreamControl.isStreaming = true;
5357
+ stepFormStreamControl.abort = () => {
5358
+ if (sourceRef.current) {
5359
+ sourceRef.current.close();
5360
+ sourceRef.current = null;
5361
+ }
5362
+ stepFormStreamControl.isStreaming = false;
5363
+ stepFormStreamControl.abort = null;
5364
+ // Stop the agent flow on the backend (same as StreamedContent.abortStreaming)
5365
+ if (sessionId) {
5366
+ stopAgentFlow({ session_id: sessionId }, baseUrl);
5367
+ }
5368
+ dispatch(setStepFormStreamData({ status: "error", chunks: [...chunksRef] }));
5369
+ };
5370
+ // Signal that streaming has started (after setting stepFormStreamControl so useEffect sees the flag)
5345
5371
  dispatch(setStepFormStreamData({ status: "streaming_start", chunks: [] }));
5372
+ // Fire DOM event so SmartBot can show stop icon (Redux gets cleared by TabularContent before parent effects run)
5373
+ window.dispatchEvent(new CustomEvent("stepFormStreamStart"));
5346
5374
  sourceRef.current = AxiosSource(endPoint, {
5347
5375
  method: "POST",
5348
5376
  headers: {
@@ -5362,11 +5390,21 @@ const ButtonContent = ({ bodyText, isFormDisabled = false, isStepFormSubmit = fa
5362
5390
  chunksRef.push(data);
5363
5391
  // If this chunk also carries [DONE], dispatch collected chunks now
5364
5392
  if (data?.message === "[DONE]") {
5393
+ stepFormStreamControl.isStreaming = false;
5394
+ stepFormStreamControl.abort = null;
5395
+ window.dispatchEvent(new CustomEvent("stepFormStreamEnd"));
5365
5396
  dispatch(setStepFormStreamData({ status: "done", chunks: [...chunksRef] }));
5366
5397
  }
5367
5398
  }
5368
5399
  else if (data?.status === "completed" || data?.message === "[DONE]") {
5369
5400
  // Stream ended — dispatch all collected chunks at once
5401
+ stepFormStreamControl.isStreaming = false;
5402
+ stepFormStreamControl.abort = null;
5403
+ window.dispatchEvent(new CustomEvent("stepFormStreamEnd"));
5404
+ // Signal tab switch to agent_response when status is "completed"
5405
+ if (data?.status === "completed") {
5406
+ window.dispatchEvent(new CustomEvent("stepFormStreamCompleted"));
5407
+ }
5370
5408
  dispatch(setStepFormStreamData({ status: "done", chunks: [...chunksRef] }));
5371
5409
  }
5372
5410
  else if (data?.message) {
@@ -5379,6 +5417,9 @@ const ButtonContent = ({ bodyText, isFormDisabled = false, isStepFormSubmit = fa
5379
5417
  });
5380
5418
  sourceRef.current.addEventListener("error", () => {
5381
5419
  // On error, still dispatch whatever we collected
5420
+ stepFormStreamControl.isStreaming = false;
5421
+ stepFormStreamControl.abort = null;
5422
+ window.dispatchEvent(new CustomEvent("stepFormStreamEnd"));
5382
5423
  dispatch(setStepFormStreamData({ status: "error", chunks: chunksRef }));
5383
5424
  });
5384
5425
  };
@@ -5432,7 +5473,7 @@ const TableContent = ({ bodyText }) => {
5432
5473
  }, [row_data]);
5433
5474
  const serverSideManualCallBack = async (manualbody, pageIndex, params) => {
5434
5475
  try {
5435
- const baseUrl = localStorage.getItem("stepForm_baseUrl") || "";
5476
+ const baseUrl = sessionStorage.getItem("stepForm_baseUrl") || "";
5436
5477
  const response = await getTableRecords(baseUrl, table_name, pageIndex + 1, page_size);
5437
5478
  return {
5438
5479
  data: response?.data?.data || [],
@@ -5990,7 +6031,7 @@ const ImageContent = ({ bodyText }) => {
5990
6031
  * @param {Array} props.formData - Array of raw widget_data items from step_form chunk
5991
6032
  * @param {number} props.messageIndex - Index for form state persistence keys
5992
6033
  */
5993
- const StepFormContent = ({ formData, messageIndex = 0, isFormDisabled = false }) => {
6034
+ const StepFormContent = ({ formData, messageIndex = 0, isFormDisabled = false, showSavedFilters = true }) => {
5994
6035
  const dispatch = useDispatch();
5995
6036
  const savedFilterSets = useSelector((state) => state.smartBotReducer.savedFilterSets);
5996
6037
  const persistedFormValues = useSelector((state) => state.smartBotReducer.persistedFormValues);
@@ -6161,7 +6202,7 @@ const StepFormContent = ({ formData, messageIndex = 0, isFormDisabled = false })
6161
6202
  });
6162
6203
  if (formFields.length === 0 && buttonItems.length === 0)
6163
6204
  return null;
6164
- return (jsxs("div", { className: "step-form-content", children: [filterSetOptions.length > 0 && (jsx("div", { style: { width: "100%", marginTop: "10px" }, children: jsx(Select, { currentOptions: filterSetCurrentOptions, setCurrentOptions: setFilterSetCurrentOptions, label: "Saved Filter Sets", labelOrientation: "top", isRequired: false, isDisabled: savedFilterDisabled, handleChange: (selected) => onFilterSetChange(selected), isCloseWhenClickOutside: true, setIsOpen: setIsFilterSetOpen, isOpen: isFilterSetOpen, selectedOptions: selectedFilterSet, setSelectedOptions: setSelectedFilterSet, initialOptions: filterSetOptions, isMulti: false, isClearable: true }) })), filterSetOptions.length > 0 && (jsx("hr", { style: { border: "none", borderTop: "1px solid #E0E0E0", margin: "12px 0" } })), jsx("div", { style: {
6205
+ return (jsxs("div", { className: "step-form-content", children: [showSavedFilters && filterSetOptions.length > 0 && (jsx("div", { style: { width: "100%", marginTop: "10px" }, children: jsx(Select, { currentOptions: filterSetCurrentOptions, setCurrentOptions: setFilterSetCurrentOptions, label: "Saved Filter Sets", labelOrientation: "top", isRequired: false, isDisabled: savedFilterDisabled, handleChange: (selected) => onFilterSetChange(selected), isCloseWhenClickOutside: true, setIsOpen: setIsFilterSetOpen, isOpen: isFilterSetOpen, selectedOptions: selectedFilterSet, setSelectedOptions: setSelectedFilterSet, initialOptions: filterSetOptions, isMulti: false, isClearable: true }) })), showSavedFilters && filterSetOptions.length > 0 && (jsx("hr", { style: { border: "none", borderTop: "1px solid #E0E0E0", margin: "12px 0" } })), jsx("div", { style: {
6165
6206
  ...(isFilterSelected && !isFormDisabled ? { pointerEvents: "none", opacity: 0.5 } : {}),
6166
6207
  }, children: formFields }), buttonItems] }));
6167
6208
  };
@@ -6234,8 +6275,8 @@ const useStyles$3 = makeStyles$1((theme) => ({
6234
6275
  "&.completed": {
6235
6276
  width: pxToRem(10),
6236
6277
  height: pxToRem(10),
6237
- background: colours.greyscale250,
6238
- border: `${pxToRem(3)} solid ${colours.greyscale150}`,
6278
+ background: "#4CAF50",
6279
+ border: `${pxToRem(3)} solid #C8E6C9`,
6239
6280
  boxSizing: "content-box",
6240
6281
  },
6241
6282
  "&.in-progress": {
@@ -6383,9 +6424,11 @@ const getQuestionStatus$1 = (questionSteps) => {
6383
6424
  /**
6384
6425
  * Renders a single progress bar item (main point + sub-items)
6385
6426
  */
6386
- const ProgressBarItem$1 = ({ question, questionSteps, isLast, classes, formData, isFormDisabled }) => {
6387
- const status = getQuestionStatus$1(questionSteps);
6388
- const [isExpanded, setIsExpanded] = useState(status === "in-progress" || status === "error");
6427
+ const ProgressBarItem$1 = ({ question, questionSteps, isLast, classes, formData, showSavedFilters = true, isFormDisabled, isRestreaming = false }) => {
6428
+ const baseStatus = getQuestionStatus$1(questionSteps);
6429
+ // When restreaming and this is the last item, show as in-progress
6430
+ const status = (isRestreaming && isLast) ? "in-progress" : baseStatus;
6431
+ const [isExpanded, setIsExpanded] = useState(true);
6389
6432
  const dotClass = status === "completed"
6390
6433
  ? "completed"
6391
6434
  : status === "in-progress"
@@ -6409,11 +6452,8 @@ const ProgressBarItem$1 = ({ question, questionSteps, isLast, classes, formData,
6409
6452
  if (status === "in-progress" || status === "error" || formData) {
6410
6453
  setIsExpanded(true);
6411
6454
  }
6412
- else if (status === "completed" && !formData) {
6413
- setIsExpanded(false);
6414
- }
6415
6455
  }, [status, formData]);
6416
- return (jsxs("div", { className: classes.progressItem, children: [jsxs("div", { className: classes.progressTrack, children: [jsx("div", { className: `${classes.progressDot} ${dotClass}` }), !isLast && jsx("div", { className: `${classes.progressLine} ${lineClass}` })] }), jsxs("div", { className: classes.progressContent, children: [jsxs("div", { className: classes.progressHeader, onClick: handleToggle, children: [jsx("span", { className: `${classes.progressHeaderText} ${textClass}`, children: question }), hasSubItems && (jsx(ChevronRightIcon$1, { className: `${classes.progressChevron} ${textClass} ${isExpanded ? "expanded" : ""}` }))] }), hasSubItems && isExpanded && status === "in-progress" && (jsxs("div", { className: classes.reasoningLabel, children: [jsx(SvgReasoningIcon, {}), "Reasoning..."] })), hasSubItems && isExpanded && (jsx("div", { className: classes.progressSubItems, style: { opacity: isExpanded ? 1 : 0 }, children: questionSteps.map((step, idx) => (jsxs("div", { className: classes.progressSubItem, children: [step.header, step.sub_header ? ` - ${step.sub_header}` : ""] }, idx))) })), formData && isExpanded && (jsx("div", { className: classes.stepFormContainer, children: jsx(StepFormContent, { formData: formData, isFormDisabled: isFormDisabled }) }))] })] }));
6456
+ return (jsxs("div", { className: classes.progressItem, children: [jsxs("div", { className: classes.progressTrack, children: [jsx("div", { className: `${classes.progressDot} ${dotClass}` }), !isLast && jsx("div", { className: `${classes.progressLine} ${lineClass}` })] }), jsxs("div", { className: classes.progressContent, children: [jsxs("div", { className: classes.progressHeader, onClick: handleToggle, children: [jsx("span", { className: `${classes.progressHeaderText} ${textClass}`, children: question }), hasSubItems && (jsx(ChevronRightIcon$1, { className: `${classes.progressChevron} ${textClass} ${isExpanded ? "expanded" : ""}` }))] }), hasSubItems && isExpanded && status === "in-progress" && (jsxs("div", { className: classes.reasoningLabel, children: [jsx(SvgReasoningIcon, {}), "Reasoning..."] })), hasSubItems && isExpanded && (jsx("div", { className: classes.progressSubItems, style: { maxHeight: isExpanded ? "500px" : "0", opacity: isExpanded ? 1 : 0 }, children: questionSteps.map((step, idx) => (jsxs("div", { className: classes.progressSubItem, children: [step.header, step.sub_header ? ` - ${step.sub_header}` : ""] }, idx))) })), formData && isExpanded && (jsx("div", { className: classes.stepFormContainer, children: jsx(StepFormContent, { formData: formData, isFormDisabled: isFormDisabled, showSavedFilters: showSavedFilters }) }))] })] }));
6417
6457
  };
6418
6458
  const Steps$1 = ({ steps, setSteps, done, setTabValue, setDone, finalStepDone, setFinalStepDone, stepChange, currentMode, questions = [], questionsStepsMap = {}, stepFormDataMap = {}, isFormDisabled = false, }) => {
6419
6459
  const classes = useStyles$3();
@@ -6463,7 +6503,7 @@ const Steps$1 = ({ steps, setSteps, done, setTabValue, setDone, finalStepDone, s
6463
6503
  step_status: "not-completed",
6464
6504
  },
6465
6505
  ];
6466
- return (jsx("div", { className: classes.progressBarContainer, children: jsx(ProgressBarItem$1, { question: fallbackQuestion, questionSteps: fallbackSteps, isLast: true, classes: classes, formData: null, isFormDisabled: isFormDisabled }) }));
6506
+ return (jsx("div", { className: classes.progressBarContainer, children: jsx(ProgressBarItem$1, { question: fallbackQuestion, questionSteps: fallbackSteps, isLast: true, classes: classes, formData: null, isFormDisabled: isFormDisabled, showSavedFilters: true }) }));
6467
6507
  }
6468
6508
  return (jsx("div", { className: classes.progressBarContainer, children: questions.map((question, index) => {
6469
6509
  const questionData = questionsStepsMap[question];
@@ -6474,8 +6514,10 @@ const Steps$1 = ({ steps, setSteps, done, setTabValue, setDone, finalStepDone, s
6474
6514
  step_status: "not-completed",
6475
6515
  },
6476
6516
  ];
6477
- const formData = stepFormDataMap[question] || null;
6478
- return (jsx(ProgressBarItem$1, { question: question, questionSteps: questionSteps, isLast: index === questions.length - 1, classes: classes, formData: formData, isFormDisabled: isFormDisabled }, index));
6517
+ const formEntry = stepFormDataMap[question] || null;
6518
+ const formData = formEntry ? (Array.isArray(formEntry) ? formEntry : formEntry.widgets) : null;
6519
+ const showSavedFilters = formEntry && !Array.isArray(formEntry) ? formEntry.showSavedFilters : true;
6520
+ return (jsx(ProgressBarItem$1, { question: question, questionSteps: questionSteps, isLast: index === questions.length - 1, classes: classes, formData: formData, isFormDisabled: isFormDisabled, showSavedFilters: showSavedFilters }, index));
6479
6521
  }) }));
6480
6522
  };
6481
6523
 
@@ -6729,6 +6771,7 @@ const StreamedContent = ({ botData }) => {
6729
6771
  session_id: data?.session_id || "",
6730
6772
  },
6731
6773
  }));
6774
+ return;
6732
6775
  }
6733
6776
  if (data?.message || data?.status === "step" || data?.status === "step_form" || data?.status === "thinking" || data?.status === "questions") {
6734
6777
  if (data.status === "questions") {
@@ -6855,15 +6898,27 @@ const StreamedContent = ({ botData }) => {
6855
6898
  ],
6856
6899
  },
6857
6900
  };
6858
- stepFormDataMapRef.current[currentIntent] = [...formWidgetData, stepFormSubmitButton];
6901
+ stepFormDataMapRef.current[currentIntent] = {
6902
+ widgets: [...formWidgetData, stepFormSubmitButton],
6903
+ showSavedFilters: data.show_saved_filters !== false,
6904
+ };
6859
6905
  setStepFormDataMap(cloneDeep(stepFormDataMapRef.current));
6860
6906
  }
6861
6907
  setStepChange((prev) => !prev);
6862
6908
  // Persist IDs immediately when step_form arrives (AxiosEventSource already set them)
6863
- localStorage.setItem("stepForm_sessionId", messageToStoreRef.current.sessionId || "");
6864
- localStorage.setItem("stepForm_chatId", messageToStoreRef.current.uniqueChatId || "");
6865
- localStorage.setItem("stepForm_agentId", botData.inputBody?.agent_id || "");
6866
- localStorage.setItem("stepForm_baseUrl", baseUrl || "");
6909
+ const _sid = messageToStoreRef.current.sessionId || "";
6910
+ const _cid = messageToStoreRef.current.uniqueChatId || "";
6911
+ const _aid = botData.inputBody?.agent_id || "";
6912
+ const _burl = baseUrl || "";
6913
+ sessionStorage.setItem("stepForm_sessionId", _sid);
6914
+ sessionStorage.setItem("stepForm_chatId", _cid);
6915
+ sessionStorage.setItem("stepForm_agentId", _aid);
6916
+ sessionStorage.setItem("stepForm_baseUrl", _burl);
6917
+ // Also set on module-level control object (survives async timing issues)
6918
+ stepFormStreamControl.sessionId = _sid;
6919
+ stepFormStreamControl.chatId = _cid;
6920
+ stepFormStreamControl.agentId = _aid;
6921
+ stepFormStreamControl.baseUrl = _burl;
6867
6922
  // If this is the [DONE] chunk, mark streaming as complete
6868
6923
  if (data.message === "[DONE]") {
6869
6924
  setIsStreamingDone(true);
@@ -6873,7 +6928,6 @@ const StreamedContent = ({ botData }) => {
6873
6928
  }
6874
6929
  }
6875
6930
  else if (data.message !== "[DONE]") {
6876
- setStepsDone(true);
6877
6931
  if (!thinkingDoneRef?.current && currentMode === "agent") {
6878
6932
  thinkingDoneRef.current = true;
6879
6933
  setThinkDone(true);
@@ -6900,6 +6954,10 @@ const StreamedContent = ({ botData }) => {
6900
6954
  });
6901
6955
  }
6902
6956
  else {
6957
+ // message === "[DONE]" with status "completed" — switch to agent_response tab
6958
+ if (data.status === "completed") {
6959
+ setStepsDone(true);
6960
+ }
6903
6961
  setIsStreamingDone(true);
6904
6962
  const doneState = streamStateMap.get(streamKey);
6905
6963
  if (doneState)
@@ -7017,10 +7075,15 @@ const StreamedContent = ({ botData }) => {
7017
7075
  dispatch(setCurrentAgentChatId(messageToStoreRef.current.uniqueChatId));
7018
7076
  }
7019
7077
  // Persist IDs for step form restream (ButtonContent reads these)
7020
- localStorage.setItem("stepForm_sessionId", messageToStoreRef.current.sessionId || "");
7021
- localStorage.setItem("stepForm_chatId", messageToStoreRef.current.uniqueChatId || "");
7022
- localStorage.setItem("stepForm_agentId", botData.inputBody?.agent_id || "");
7023
- localStorage.setItem("stepForm_baseUrl", baseUrl || "");
7078
+ sessionStorage.setItem("stepForm_sessionId", messageToStoreRef.current.sessionId || "");
7079
+ sessionStorage.setItem("stepForm_chatId", messageToStoreRef.current.uniqueChatId || "");
7080
+ sessionStorage.setItem("stepForm_agentId", botData.inputBody?.agent_id || "");
7081
+ sessionStorage.setItem("stepForm_baseUrl", baseUrl || "");
7082
+ // Also sync module-level control object
7083
+ stepFormStreamControl.sessionId = messageToStoreRef.current.sessionId || "";
7084
+ stepFormStreamControl.chatId = messageToStoreRef.current.uniqueChatId || "";
7085
+ stepFormStreamControl.agentId = botData.inputBody?.agent_id || "";
7086
+ stepFormStreamControl.baseUrl = baseUrl || "";
7024
7087
  let appendedDataLength = 0;
7025
7088
  // Use appendedDataFromLastChunk for field number calculation like host app
7026
7089
  if (isArray(messageToStoreRef.current.appendedDataFromLastChunk)) {
@@ -7075,7 +7138,7 @@ const StreamedContent = ({ botData }) => {
7075
7138
  newChatData: chatDataInfoRef,
7076
7139
  isTabEnabled: true,
7077
7140
  steps: cloneDeep(stepRef.current),
7078
- currentTabValue: "agent_response",
7141
+ currentTabValue: stepsDone ? "agent_response" : undefined,
7079
7142
  questions: cloneDeep(questionsRef.current),
7080
7143
  questionsStepsMap: cloneDeep(questionsStepsMapRef.current),
7081
7144
  stepFormDataMap: cloneDeep(stepFormDataMapRef.current),
@@ -7161,7 +7224,7 @@ const StreamedContent = ({ botData }) => {
7161
7224
  newChatData: chatDataInfoRef,
7162
7225
  isTabEnabled: true,
7163
7226
  steps: cloneDeep(stepRef.current),
7164
- currentTabValue: "agent_response",
7227
+ currentTabValue: stepsDone ? "agent_response" : undefined,
7165
7228
  questions: cloneDeep(questionsRef.current),
7166
7229
  questionsStepsMap: cloneDeep(questionsStepsMapRef.current),
7167
7230
  stepFormDataMap: cloneDeep(stepFormDataMapRef.current),
@@ -7373,8 +7436,8 @@ const useStyles$2 = makeStyles$1((theme) => ({
7373
7436
  "&.completed": {
7374
7437
  width: pxToRem(10),
7375
7438
  height: pxToRem(10),
7376
- background: colours.greyscale250,
7377
- border: `${pxToRem(3)} solid ${colours.greyscale150}`,
7439
+ background: "#4CAF50",
7440
+ border: `${pxToRem(3)} solid #C8E6C9`,
7378
7441
  boxSizing: "content-box",
7379
7442
  },
7380
7443
  "&.in-progress": {
@@ -7516,11 +7579,11 @@ const getQuestionStatus = (questionSteps) => {
7516
7579
  /**
7517
7580
  * Renders a single progress bar item (main point + sub-items)
7518
7581
  */
7519
- const ProgressBarItem = ({ question, questionSteps, isLast, classes, formData, isFormDisabled, isRestreaming = false }) => {
7582
+ const ProgressBarItem = ({ question, questionSteps, isLast, classes, formData, isFormDisabled, isRestreaming = false, showSavedFilters = true }) => {
7520
7583
  const baseStatus = getQuestionStatus(questionSteps);
7521
7584
  // When restreaming and this is the last item, show as in-progress
7522
7585
  const status = (isRestreaming && isLast) ? "in-progress" : baseStatus;
7523
- const [isExpanded, setIsExpanded] = useState(status === "in-progress" || status === "error");
7586
+ const [isExpanded, setIsExpanded] = useState(true);
7524
7587
  const dotClass = status === "completed"
7525
7588
  ? "completed"
7526
7589
  : status === "in-progress"
@@ -7545,9 +7608,9 @@ const ProgressBarItem = ({ question, questionSteps, isLast, classes, formData, i
7545
7608
  setIsExpanded(true);
7546
7609
  }
7547
7610
  }, [status, formData]);
7548
- return (jsxs("div", { className: classes.progressItem, children: [jsxs("div", { className: classes.progressTrack, children: [jsx("div", { className: `${classes.progressDot} ${dotClass}` }), !isLast && jsx("div", { className: `${classes.progressLine} ${lineClass}` })] }), jsxs("div", { className: classes.progressContent, children: [jsxs("div", { className: classes.progressHeader, onClick: handleToggle, children: [jsx("span", { className: `${classes.progressHeaderText} ${textClass}`, children: question }), hasSubItems && (jsx(ChevronRightIcon$1, { className: `${classes.progressChevron} ${textClass} ${isExpanded ? "expanded" : ""}` }))] }), hasSubItems && isExpanded && status === "in-progress" && (jsxs("div", { className: classes.reasoningLabel, children: [jsx(SvgReasoningIcon, {}), "Reasoning..."] })), hasSubItems && isExpanded && (jsx("div", { className: classes.progressSubItems, style: { maxHeight: isExpanded ? "500px" : "0", opacity: isExpanded ? 1 : 0 }, children: questionSteps.map((step, idx) => (jsxs("div", { className: classes.progressSubItem, children: [step.header, step.sub_header ? ` - ${step.sub_header}` : ""] }, idx))) })), formData && isExpanded && (jsx("div", { className: classes.stepFormContainer, children: jsx(StepFormContent, { formData: formData, isFormDisabled: isFormDisabled }) }))] })] }));
7611
+ return (jsxs("div", { className: classes.progressItem, children: [jsxs("div", { className: classes.progressTrack, children: [jsx("div", { className: `${classes.progressDot} ${dotClass}` }), !isLast && jsx("div", { className: `${classes.progressLine} ${lineClass}` })] }), jsxs("div", { className: classes.progressContent, children: [jsxs("div", { className: classes.progressHeader, onClick: handleToggle, children: [jsx("span", { className: `${classes.progressHeaderText} ${textClass}`, children: question }), hasSubItems && (jsx(ChevronRightIcon$1, { className: `${classes.progressChevron} ${textClass} ${isExpanded ? "expanded" : ""}` }))] }), hasSubItems && isExpanded && status === "in-progress" && (jsxs("div", { className: classes.reasoningLabel, children: [jsx(SvgReasoningIcon, {}), "Reasoning..."] })), hasSubItems && isExpanded && (jsx("div", { className: classes.progressSubItems, style: { maxHeight: isExpanded ? "500px" : "0", opacity: isExpanded ? 1 : 0 }, children: questionSteps.map((step, idx) => (jsxs("div", { className: classes.progressSubItem, children: [step.header, step.sub_header ? ` - ${step.sub_header}` : ""] }, idx))) })), formData && isExpanded && (jsx("div", { className: classes.stepFormContainer, children: jsx(StepFormContent, { formData: formData, isFormDisabled: isFormDisabled, showSavedFilters: showSavedFilters }) }))] })] }));
7549
7612
  };
7550
- const Steps = ({ steps, questions = [], questionsStepsMap = {}, stepFormDataMap = {}, isFormDisabled = false, isRestreaming = false }) => {
7613
+ const Steps = ({ steps, questions = [], questionsStepsMap = {}, stepFormDataMap = {}, isFormDisabled = false, activeFormIntent = null, isRestreaming = false }) => {
7551
7614
  const classes = useStyles$2();
7552
7615
  useState(false);
7553
7616
  const hasQuestions = questions.length > 0;
@@ -7567,8 +7630,15 @@ const Steps = ({ steps, questions = [], questionsStepsMap = {}, stepFormDataMap
7567
7630
  step_status: "completed",
7568
7631
  },
7569
7632
  ];
7570
- const formData = stepFormDataMap[question] || null;
7571
- return (jsx(ProgressBarItem, { question: question, questionSteps: questionSteps, isLast: index === questions.length - 1, classes: classes, formData: formData, isFormDisabled: isFormDisabled, isRestreaming: isRestreaming }, index));
7633
+ const formEntry = stepFormDataMap[question] || null;
7634
+ // Support both old array format and new object format { widgets, showSavedFilters }
7635
+ const formData = formEntry ? (Array.isArray(formEntry) ? formEntry : formEntry.widgets) : null;
7636
+ const showSavedFilters = formEntry && !Array.isArray(formEntry) ? formEntry.showSavedFilters : true;
7637
+ // If activeFormIntent is set, only the matching form is enabled; all others stay disabled
7638
+ const formDisabledForThis = activeFormIntent
7639
+ ? question !== activeFormIntent
7640
+ : isFormDisabled;
7641
+ return (jsx(ProgressBarItem, { question: question, questionSteps: questionSteps, isLast: index === questions.length - 1, classes: classes, formData: formData, isFormDisabled: formDisabledForThis, isRestreaming: isRestreaming, showSavedFilters: showSavedFilters }, index));
7572
7642
  }) }));
7573
7643
  };
7574
7644
 
@@ -7600,6 +7670,7 @@ const TabularContent = ({ steps: initialSteps, currentTabValue, children, questi
7600
7670
  const [isRestreaming, setIsRestreaming] = useState(false);
7601
7671
  const [stepFormSubmitted, setStepFormSubmitted] = useState(false);
7602
7672
  const [hasNewStepFormFromRestream, setHasNewStepFormFromRestream] = useState(false);
7673
+ const [activeFormIntent, setActiveFormIntent] = useState(null);
7603
7674
  // Refs for accumulating state during streaming (avoids stale closures)
7604
7675
  const stepsRef = useRef(stepsState);
7605
7676
  const questionsRef = useRef(questionsState);
@@ -7608,6 +7679,16 @@ const TabularContent = ({ steps: initialSteps, currentTabValue, children, questi
7608
7679
  const handleChangeTabValue = (_event, newValue) => {
7609
7680
  setTabValue(newValue);
7610
7681
  };
7682
+ // Switch to agent_response tab when ButtonContent's nth init stream completes with status "completed"
7683
+ useEffect(() => {
7684
+ const handleStepFormCompleted = () => {
7685
+ setTabValue("agent_response");
7686
+ };
7687
+ window.addEventListener("stepFormStreamCompleted", handleStepFormCompleted);
7688
+ return () => {
7689
+ window.removeEventListener("stepFormStreamCompleted", handleStepFormCompleted);
7690
+ };
7691
+ }, []);
7611
7692
  // Render a widget item from SSE data
7612
7693
  const renderWidget = (item, index) => {
7613
7694
  try {
@@ -7694,9 +7775,11 @@ const TabularContent = ({ steps: initialSteps, currentTabValue, children, questi
7694
7775
  },
7695
7776
  ];
7696
7777
  }
7697
- const intentSteps = newQuestionsStepsMap[currentIntent];
7698
- if (intentSteps.length === 1 && intentSteps[0].header === "Processing Request") {
7699
- intentSteps[0].step_status = "completed";
7778
+ let intentSteps = newQuestionsStepsMap[currentIntent];
7779
+ // Remove placeholder if the real step has a header
7780
+ if (newStep.header && intentSteps.length === 1 && intentSteps[0].header === "Processing Request") {
7781
+ intentSteps = [];
7782
+ newQuestionsStepsMap[currentIntent] = intentSteps;
7700
7783
  }
7701
7784
  const existingStepIdx = intentSteps.findIndex((s) => s.header === newStep.header);
7702
7785
  if (existingStepIdx !== -1) {
@@ -7730,7 +7813,10 @@ const TabularContent = ({ steps: initialSteps, currentTabValue, children, questi
7730
7813
  ],
7731
7814
  },
7732
7815
  };
7733
- newStepFormDataMap[currentIntent] = [...formWidgetData, submitButton];
7816
+ newStepFormDataMap[currentIntent] = {
7817
+ widgets: [...formWidgetData, submitButton],
7818
+ showSavedFilters: data.show_saved_filters !== false,
7819
+ };
7734
7820
  }
7735
7821
  }
7736
7822
  if (data.status === "widget") {
@@ -7757,10 +7843,16 @@ const TabularContent = ({ steps: initialSteps, currentTabValue, children, questi
7757
7843
  setWidgetContent((prev) => [...prev, ...newWidgets]);
7758
7844
  }
7759
7845
  // If the response contains a new step_form, reset stepFormSubmitted and mark new form as active
7760
- const hasNewStepForm = chunks.some((c) => c.status === "step_form");
7761
- if (hasNewStepForm) {
7846
+ const lastStepFormChunk = [...chunks].reverse().find((c) => c.status === "step_form");
7847
+ if (lastStepFormChunk) {
7848
+ const formWidgetData = isArray$2(lastStepFormChunk.widget_data) ? lastStepFormChunk.widget_data : [lastStepFormChunk.widget_data];
7849
+ const latestIntent = lastStepFormChunk.current_intent || formWidgetData?.[0]?.current_intent;
7762
7850
  setStepFormSubmitted(false);
7763
7851
  setHasNewStepFormFromRestream(true);
7852
+ setActiveFormIntent(latestIntent || null);
7853
+ // Clear stale persisted form values and context so the new form starts fresh
7854
+ dispatch(clearPersistedFormValues());
7855
+ dispatch(setChatbotContext({}));
7764
7856
  }
7765
7857
  setIsRestreaming(false);
7766
7858
  }, [stepFormStreamData]);
@@ -7778,7 +7870,7 @@ const TabularContent = ({ steps: initialSteps, currentTabValue, children, questi
7778
7870
  icon: jsx(PsychologyOutlinedIcon, { fontSize: "large" }),
7779
7871
  },
7780
7872
  ], tabPanels: [
7781
- jsx(Steps, { steps: stepsState, questions: questionsState, questionsStepsMap: questionsStepsMapState, stepFormDataMap: stepFormDataMapState, isFormDisabled: hasNewStepFormFromRestream ? false : ((isFormDisabled && !isRestreaming) || stepFormSubmitted), isRestreaming: isRestreaming }),
7873
+ jsx(Steps, { steps: stepsState, questions: questionsState, questionsStepsMap: questionsStepsMapState, stepFormDataMap: stepFormDataMapState, isFormDisabled: (isFormDisabled && !isRestreaming) || stepFormSubmitted, activeFormIntent: hasNewStepFormFromRestream ? activeFormIntent : null, isRestreaming: isRestreaming }),
7782
7874
  jsxs(AgentResponse, { children: [children, renderedWidgets.length > 0 && (jsx("div", { className: "restream-widget-content", children: renderedWidgets }))] }),
7783
7875
  ], value: tabValue }) }));
7784
7876
  };
@@ -11532,6 +11624,35 @@ const SmartBot = (props) => {
11532
11624
  setFieldNumber,
11533
11625
  setAdditionalArgs,
11534
11626
  });
11627
+ // Show/hide stop icon when step-form restream (second init API from ButtonContent) starts/ends.
11628
+ // Must live here (SmartBot) because StreamedContent unmounts after the first stream completes.
11629
+ useEffect(() => {
11630
+ const handleStepFormStreamStart = () => {
11631
+ setIsStop(true);
11632
+ const abortStepFormStream = () => {
11633
+ if (stepFormStreamControl.abort) {
11634
+ stepFormStreamControl.abort();
11635
+ }
11636
+ setIsStop(false);
11637
+ };
11638
+ setFunctionsState((prev) => ({
11639
+ ...prev,
11640
+ abortStreaming: abortStepFormStream,
11641
+ }));
11642
+ if (functionsRef?.current) {
11643
+ functionsRef.current.abortStreaming = abortStepFormStream;
11644
+ }
11645
+ };
11646
+ const handleStepFormStreamEnd = () => {
11647
+ setIsStop(false);
11648
+ };
11649
+ window.addEventListener("stepFormStreamStart", handleStepFormStreamStart);
11650
+ window.addEventListener("stepFormStreamEnd", handleStepFormStreamEnd);
11651
+ return () => {
11652
+ window.removeEventListener("stepFormStreamStart", handleStepFormStreamStart);
11653
+ window.removeEventListener("stepFormStreamEnd", handleStepFormStreamEnd);
11654
+ };
11655
+ }, []);
11535
11656
  const fetchCustomBotConfigurations = async () => {
11536
11657
  try {
11537
11658
  // const response = await fetchCustomBotConfig(baseUrl);