impact-chatbot 2.3.68 → 2.3.70

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.cjs.js CHANGED
@@ -30,6 +30,7 @@ var utils = require('core/Utils/functions/utils');
30
30
  var impactUiV3 = require('impact-ui-v3');
31
31
  var axios = require('axios');
32
32
  var isArray$1 = require('lodash/isArray');
33
+ var isEmpty$1 = require('lodash/isEmpty');
33
34
  var chatbotServices = require('core/commonComponents/smartBot/services/chatbot-services');
34
35
  var AgGridComponent = require('core/Utils/agGrid');
35
36
  var agGridColumnFormatter = require('core/Utils/agGrid/column-formatter');
@@ -5689,6 +5690,15 @@ const ButtonContent = ({ bodyText, isFormDisabled = false, isStepFormSubmit = fa
5689
5690
  }
5690
5691
  }
5691
5692
  else if (data?.status === "completed" || data?.status === "follow-up" || data?.message === "[DONE]") {
5693
+ // Extract widget_data from completed/[DONE] chunks (e.g. graph widgets)
5694
+ if (!isEmpty$1(data?.widget_data)) {
5695
+ chunksRef.push({ ...data, status: "widget" });
5696
+ dispatch(smartBotActions.setStepFormStreamData({
5697
+ status: "widget_chunk",
5698
+ chunks: [{ ...data, status: "widget" }],
5699
+ sessionId,
5700
+ }));
5701
+ }
5692
5702
  // Clear minimized widget on completion
5693
5703
  if (data?.status === "completed") {
5694
5704
  dispatch(smartBotActions.setMinimizedStreamData(null));
@@ -6754,6 +6764,7 @@ const SliderContent = ({ bodyText, isFormDisabled = false, messageIndex }) => {
6754
6764
 
6755
6765
  const INITIAL_DISPLAY_COUNT = 100;
6756
6766
  const LOAD_MORE_COUNT = 100;
6767
+ const SEARCH_DISPLAY_LIMIT = 500;
6757
6768
  const formatOption = (option) => ({
6758
6769
  ...option,
6759
6770
  label: replaceSpecialCharacter(option.label.toString()),
@@ -6771,6 +6782,8 @@ const SelectContent = ({ bodyText, isFormDisabled = false, messageIndex }) => {
6771
6782
  const [isAllSelected, setIsAllSelected] = React.useState(false);
6772
6783
  const [initialOptions, setInitialOptions] = React.useState([]);
6773
6784
  const allOptionsRef = React.useRef([]);
6785
+ const isSearchActiveRef = React.useRef(false);
6786
+ const searchTermRef = React.useRef("");
6774
6787
  const chatbotContext = reactRedux.useSelector((state) => state.smartBotReducer.chatbotContext);
6775
6788
  const heirarchyKeyValuePairs = reactRedux.useSelector((state) => state.smartBotReducer.heirarchyKeyValuePairs);
6776
6789
  const dispatch = reactRedux.useDispatch();
@@ -6863,6 +6876,40 @@ const SelectContent = ({ bodyText, isFormDisabled = false, messageIndex }) => {
6863
6876
  setCurrentOptions(initialSlice);
6864
6877
  }
6865
6878
  }, [isCascading]);
6879
+ // Custom search handler: searches ALL options (not just the loaded chunk)
6880
+ // Supports comma-separated values for multi-search
6881
+ const handleSearch = React.useCallback((event) => {
6882
+ const rawInput = event?.target?.value || "";
6883
+ searchTermRef.current = rawInput;
6884
+ const trimmed = rawInput.trim();
6885
+ if (!trimmed) {
6886
+ // Reset to initial lazy-loaded chunk
6887
+ isSearchActiveRef.current = false;
6888
+ const resetSlice = formatSlice(allOptionsRef.current, 0, INITIAL_DISPLAY_COUNT);
6889
+ setCurrentOptions(resetSlice);
6890
+ setInitialOptions(resetSlice);
6891
+ setIsAllSelected(false);
6892
+ return;
6893
+ }
6894
+ isSearchActiveRef.current = true;
6895
+ // Parse comma-separated terms
6896
+ const terms = trimmed
6897
+ .split(",")
6898
+ .map((t) => t.trim().toLowerCase())
6899
+ .filter(Boolean);
6900
+ // Search across ALL options, not just the loaded chunk
6901
+ const allRaw = allOptionsRef.current;
6902
+ const filtered = allRaw.filter((option) => {
6903
+ const labelLower = option.label?.toString().toLowerCase() || "";
6904
+ const valueLower = option.value?.toString().toLowerCase() || "";
6905
+ return terms.some((term) => labelLower.includes(term) || valueLower.includes(term));
6906
+ });
6907
+ // Format and cap the results to avoid UI freeze
6908
+ const formatted = filtered.slice(0, SEARCH_DISPLAY_LIMIT).map(formatOption);
6909
+ setCurrentOptions(formatted);
6910
+ setInitialOptions(formatted);
6911
+ setIsAllSelected(false);
6912
+ }, []);
6866
6913
  return (jsxRuntime.jsx("div", { style: { width: "100%", marginTop: "10px" }, children: jsxRuntime.jsx(impactUiV3.Select, { currentOptions: currentOptions, setCurrentOptions: setCurrentOptions, label: heirarchyKeyValuePairs[paramName] || label, labelOrientation: labelOrientation,
6867
6914
  // inputPosition={inputPosition}
6868
6915
  // header={header}
@@ -6884,6 +6931,11 @@ const SelectContent = ({ bodyText, isFormDisabled = false, messageIndex }) => {
6884
6931
  }
6885
6932
  }, handleChange: (selected) => onChange(selected), isCloseWhenClickOutside: true, setIsOpen: (open) => {
6886
6933
  setIsOpen(open);
6934
+ // When dropdown closes after a filtered select-all on a subset,
6935
+ // reset the isAllSelected flag so scroll-to-load-more doesn't auto-select more items
6936
+ if (!open && isAllSelected && currentSelectedOptions.length < allOptionsRef.current.length) {
6937
+ setIsAllSelected(false);
6938
+ }
6887
6939
  if (isCascading) {
6888
6940
  if (open) {
6889
6941
  // Lazy fetch: trigger cross-filter API call when dropdown opens for the first time
@@ -6910,7 +6962,10 @@ const SelectContent = ({ bodyText, isFormDisabled = false, messageIndex }) => {
6910
6962
  }
6911
6963
  }
6912
6964
  }
6913
- }, isOpen: isOpen, selectedOptions: currentSelectedOptions, setSelectedOptions: setCurrentSelectedOptions, initialOptions: initialOptions, isMulti: isMulti, isSelectAll: isAllSelected, setIsSelectAll: setIsAllSelected, toggleSelectAll: true, isLoading: isCascading ? crossFilterCtx.loadingMap[paramName] : false, emptyMessage: isCascading && crossFilterCtx.loadingMap[paramName] ? "Loading values..." : "No options available", isWithSearch: isMulti ? true : false, onMenuScrollToBottom: () => {
6965
+ }, isOpen: isOpen, selectedOptions: currentSelectedOptions, setSelectedOptions: setCurrentSelectedOptions, initialOptions: initialOptions, isMulti: isMulti, isSelectAll: isAllSelected, setIsSelectAll: setIsAllSelected, toggleSelectAll: true, isLoading: isCascading ? crossFilterCtx.loadingMap[paramName] : false, emptyMessage: isCascading && crossFilterCtx.loadingMap[paramName] ? "Loading values..." : "No options available", isWithSearch: isMulti ? true : false, onSearch: handleSearch, onMenuScrollToBottom: () => {
6966
+ // Only allow scroll-to-load-more when NOT in search mode
6967
+ if (isSearchActiveRef.current)
6968
+ return;
6914
6969
  const allRaw = allOptionsRef.current;
6915
6970
  if (allRaw.length > 0 && currentOptions.length < allRaw.length) {
6916
6971
  const nextCount = Math.min(currentOptions.length + LOAD_MORE_COUNT, allRaw.length);
@@ -6924,33 +6979,53 @@ const SelectContent = ({ bodyText, isFormDisabled = false, messageIndex }) => {
6924
6979
  }
6925
6980
  }, onSelectAll: (e) => {
6926
6981
  if (e && e.target.checked) {
6927
- setCurrentSelectedOptions([...currentOptions]);
6982
+ // When search is active, select only the filtered/visible options
6983
+ // When no search is active, select ALL options from the full dataset
6984
+ let optionsToSelect;
6985
+ let valuesToDispatch;
6986
+ if (isSearchActiveRef.current) {
6987
+ optionsToSelect = [...currentOptions];
6988
+ valuesToDispatch = currentOptions.map((opt) => opt.value);
6989
+ }
6990
+ else {
6991
+ optionsToSelect = allOptionsRef.current.map(formatOption);
6992
+ valuesToDispatch = allOptionsRef.current.map((opt) => opt.value);
6993
+ }
6994
+ setCurrentSelectedOptions(optionsToSelect);
6928
6995
  setIsAllSelected(true);
6929
- const allValues = allOptionsRef.current.map((opt) => opt.value);
6930
6996
  dispatch(smartBotActions.setChatbotContext({
6931
6997
  ...chatbotContext,
6932
6998
  [bodyText?.paramName]: {
6933
6999
  ...chatbotContext?.[bodyText?.paramName],
6934
- [bodyText?.paramName]: allValues,
7000
+ [bodyText?.paramName]: valuesToDispatch,
6935
7001
  updated: true,
6936
7002
  },
6937
7003
  }));
6938
- dispatch(smartBotActions.setPersistedFormValues({ [formKey]: currentOptions }));
7004
+ dispatch(smartBotActions.setPersistedFormValues({ [formKey]: optionsToSelect }));
6939
7005
  // Notify cross-filter context if cascading is active
6940
7006
  if (isCascading) {
6941
- crossFilterCtx.onFilterChange(paramName, allValues);
7007
+ crossFilterCtx.onFilterChange(paramName, valuesToDispatch);
6942
7008
  }
6943
7009
  }
6944
7010
  else {
6945
7011
  setCurrentSelectedOptions([]);
6946
7012
  setIsAllSelected(false);
7013
+ dispatch(smartBotActions.setChatbotContext({
7014
+ ...chatbotContext,
7015
+ [bodyText?.paramName]: {
7016
+ ...chatbotContext?.[bodyText?.paramName],
7017
+ [bodyText?.paramName]: [],
7018
+ updated: true,
7019
+ },
7020
+ }));
7021
+ dispatch(smartBotActions.setPersistedFormValues({ [formKey]: [] }));
6947
7022
  // Notify cross-filter context of deselection
6948
7023
  if (isCascading) {
6949
7024
  crossFilterCtx.onFilterChange(paramName, []);
6950
7025
  }
6951
7026
  }
6952
- }, customPlaceholderAfterSelect: isAllSelected && allOptionsRef.current.length > 0
6953
- ? allOptionsRef.current.length
7027
+ }, customPlaceholderAfterSelect: currentSelectedOptions.length > 0
7028
+ ? currentSelectedOptions.length
6954
7029
  : null }) }));
6955
7030
  };
6956
7031
 
@@ -10080,7 +10155,13 @@ const TabularContent = ({ steps: initialSteps, currentTabValue, children, questi
10080
10155
  };
10081
10156
  }
10082
10157
  }
10083
- if (data.status === "widget") ;
10158
+ if (data.status === "widget") {
10159
+ const widgetItems = isArray$1(data.widget_data) ? data.widget_data : [data.widget_data];
10160
+ widgetItems.forEach((item) => {
10161
+ if (item)
10162
+ newWidgets.push(item);
10163
+ });
10164
+ }
10084
10165
  if (data.status === "content" && data.message) {
10085
10166
  newWidgets.push({ type: "text", response: data.message });
10086
10167
  }
@@ -10095,7 +10176,8 @@ const TabularContent = ({ steps: initialSteps, currentTabValue, children, questi
10095
10176
  setQuestionsStepsMapState(lodash.cloneDeep(newQuestionsStepsMap));
10096
10177
  setStepFormDataMapState(lodash.cloneDeep(newStepFormDataMap));
10097
10178
  if (newWidgets.length > 0) {
10098
- setWidgetContent((prev) => [...prev, ...newWidgets]);
10179
+ // Replace (not append) to avoid duplicates from real-time widget_chunk dispatches
10180
+ setWidgetContent(newWidgets);
10099
10181
  }
10100
10182
  // If the response contains a new step_form, reset stepFormSubmitted and mark new form as active
10101
10183
  const lastStepFormChunk = [...chunks].reverse().find((c) => c.status === "step_form");