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.esm.js CHANGED
@@ -27,6 +27,7 @@ import { fetchBaseUrl, replaceSpecialCharacter as replaceSpecialCharacter$1, fet
27
27
  import { Button, Modal, Slider, Select, DatePicker, DateRangePicker, Checkbox, RadioButtonGroup, Input, Tabs, Loader, Tooltip, ChatBotComponent } from 'impact-ui-v3';
28
28
  import axios from 'axios';
29
29
  import isArray$2 from 'lodash/isArray';
30
+ import isEmpty$2 from 'lodash/isEmpty';
30
31
  import { stopAgentFlow } from 'core/commonComponents/smartBot/services/chatbot-services';
31
32
  import AgGridComponent from 'core/Utils/agGrid';
32
33
  import agGridColumnFormatter from 'core/Utils/agGrid/column-formatter';
@@ -5667,6 +5668,15 @@ const ButtonContent = ({ bodyText, isFormDisabled = false, isStepFormSubmit = fa
5667
5668
  }
5668
5669
  }
5669
5670
  else if (data?.status === "completed" || data?.status === "follow-up" || data?.message === "[DONE]") {
5671
+ // Extract widget_data from completed/[DONE] chunks (e.g. graph widgets)
5672
+ if (!isEmpty$2(data?.widget_data)) {
5673
+ chunksRef.push({ ...data, status: "widget" });
5674
+ dispatch(setStepFormStreamData({
5675
+ status: "widget_chunk",
5676
+ chunks: [{ ...data, status: "widget" }],
5677
+ sessionId,
5678
+ }));
5679
+ }
5670
5680
  // Clear minimized widget on completion
5671
5681
  if (data?.status === "completed") {
5672
5682
  dispatch(setMinimizedStreamData(null));
@@ -6732,6 +6742,7 @@ const SliderContent = ({ bodyText, isFormDisabled = false, messageIndex }) => {
6732
6742
 
6733
6743
  const INITIAL_DISPLAY_COUNT = 100;
6734
6744
  const LOAD_MORE_COUNT = 100;
6745
+ const SEARCH_DISPLAY_LIMIT = 500;
6735
6746
  const formatOption = (option) => ({
6736
6747
  ...option,
6737
6748
  label: replaceSpecialCharacter(option.label.toString()),
@@ -6749,6 +6760,8 @@ const SelectContent = ({ bodyText, isFormDisabled = false, messageIndex }) => {
6749
6760
  const [isAllSelected, setIsAllSelected] = useState(false);
6750
6761
  const [initialOptions, setInitialOptions] = useState([]);
6751
6762
  const allOptionsRef = useRef([]);
6763
+ const isSearchActiveRef = useRef(false);
6764
+ const searchTermRef = useRef("");
6752
6765
  const chatbotContext = useSelector((state) => state.smartBotReducer.chatbotContext);
6753
6766
  const heirarchyKeyValuePairs = useSelector((state) => state.smartBotReducer.heirarchyKeyValuePairs);
6754
6767
  const dispatch = useDispatch();
@@ -6841,6 +6854,40 @@ const SelectContent = ({ bodyText, isFormDisabled = false, messageIndex }) => {
6841
6854
  setCurrentOptions(initialSlice);
6842
6855
  }
6843
6856
  }, [isCascading]);
6857
+ // Custom search handler: searches ALL options (not just the loaded chunk)
6858
+ // Supports comma-separated values for multi-search
6859
+ const handleSearch = useCallback((event) => {
6860
+ const rawInput = event?.target?.value || "";
6861
+ searchTermRef.current = rawInput;
6862
+ const trimmed = rawInput.trim();
6863
+ if (!trimmed) {
6864
+ // Reset to initial lazy-loaded chunk
6865
+ isSearchActiveRef.current = false;
6866
+ const resetSlice = formatSlice(allOptionsRef.current, 0, INITIAL_DISPLAY_COUNT);
6867
+ setCurrentOptions(resetSlice);
6868
+ setInitialOptions(resetSlice);
6869
+ setIsAllSelected(false);
6870
+ return;
6871
+ }
6872
+ isSearchActiveRef.current = true;
6873
+ // Parse comma-separated terms
6874
+ const terms = trimmed
6875
+ .split(",")
6876
+ .map((t) => t.trim().toLowerCase())
6877
+ .filter(Boolean);
6878
+ // Search across ALL options, not just the loaded chunk
6879
+ const allRaw = allOptionsRef.current;
6880
+ const filtered = allRaw.filter((option) => {
6881
+ const labelLower = option.label?.toString().toLowerCase() || "";
6882
+ const valueLower = option.value?.toString().toLowerCase() || "";
6883
+ return terms.some((term) => labelLower.includes(term) || valueLower.includes(term));
6884
+ });
6885
+ // Format and cap the results to avoid UI freeze
6886
+ const formatted = filtered.slice(0, SEARCH_DISPLAY_LIMIT).map(formatOption);
6887
+ setCurrentOptions(formatted);
6888
+ setInitialOptions(formatted);
6889
+ setIsAllSelected(false);
6890
+ }, []);
6844
6891
  return (jsx("div", { style: { width: "100%", marginTop: "10px" }, children: jsx(Select, { currentOptions: currentOptions, setCurrentOptions: setCurrentOptions, label: heirarchyKeyValuePairs[paramName] || label, labelOrientation: labelOrientation,
6845
6892
  // inputPosition={inputPosition}
6846
6893
  // header={header}
@@ -6862,6 +6909,11 @@ const SelectContent = ({ bodyText, isFormDisabled = false, messageIndex }) => {
6862
6909
  }
6863
6910
  }, handleChange: (selected) => onChange(selected), isCloseWhenClickOutside: true, setIsOpen: (open) => {
6864
6911
  setIsOpen(open);
6912
+ // When dropdown closes after a filtered select-all on a subset,
6913
+ // reset the isAllSelected flag so scroll-to-load-more doesn't auto-select more items
6914
+ if (!open && isAllSelected && currentSelectedOptions.length < allOptionsRef.current.length) {
6915
+ setIsAllSelected(false);
6916
+ }
6865
6917
  if (isCascading) {
6866
6918
  if (open) {
6867
6919
  // Lazy fetch: trigger cross-filter API call when dropdown opens for the first time
@@ -6888,7 +6940,10 @@ const SelectContent = ({ bodyText, isFormDisabled = false, messageIndex }) => {
6888
6940
  }
6889
6941
  }
6890
6942
  }
6891
- }, 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: () => {
6943
+ }, 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: () => {
6944
+ // Only allow scroll-to-load-more when NOT in search mode
6945
+ if (isSearchActiveRef.current)
6946
+ return;
6892
6947
  const allRaw = allOptionsRef.current;
6893
6948
  if (allRaw.length > 0 && currentOptions.length < allRaw.length) {
6894
6949
  const nextCount = Math.min(currentOptions.length + LOAD_MORE_COUNT, allRaw.length);
@@ -6902,33 +6957,53 @@ const SelectContent = ({ bodyText, isFormDisabled = false, messageIndex }) => {
6902
6957
  }
6903
6958
  }, onSelectAll: (e) => {
6904
6959
  if (e && e.target.checked) {
6905
- setCurrentSelectedOptions([...currentOptions]);
6960
+ // When search is active, select only the filtered/visible options
6961
+ // When no search is active, select ALL options from the full dataset
6962
+ let optionsToSelect;
6963
+ let valuesToDispatch;
6964
+ if (isSearchActiveRef.current) {
6965
+ optionsToSelect = [...currentOptions];
6966
+ valuesToDispatch = currentOptions.map((opt) => opt.value);
6967
+ }
6968
+ else {
6969
+ optionsToSelect = allOptionsRef.current.map(formatOption);
6970
+ valuesToDispatch = allOptionsRef.current.map((opt) => opt.value);
6971
+ }
6972
+ setCurrentSelectedOptions(optionsToSelect);
6906
6973
  setIsAllSelected(true);
6907
- const allValues = allOptionsRef.current.map((opt) => opt.value);
6908
6974
  dispatch(setChatbotContext({
6909
6975
  ...chatbotContext,
6910
6976
  [bodyText?.paramName]: {
6911
6977
  ...chatbotContext?.[bodyText?.paramName],
6912
- [bodyText?.paramName]: allValues,
6978
+ [bodyText?.paramName]: valuesToDispatch,
6913
6979
  updated: true,
6914
6980
  },
6915
6981
  }));
6916
- dispatch(setPersistedFormValues({ [formKey]: currentOptions }));
6982
+ dispatch(setPersistedFormValues({ [formKey]: optionsToSelect }));
6917
6983
  // Notify cross-filter context if cascading is active
6918
6984
  if (isCascading) {
6919
- crossFilterCtx.onFilterChange(paramName, allValues);
6985
+ crossFilterCtx.onFilterChange(paramName, valuesToDispatch);
6920
6986
  }
6921
6987
  }
6922
6988
  else {
6923
6989
  setCurrentSelectedOptions([]);
6924
6990
  setIsAllSelected(false);
6991
+ dispatch(setChatbotContext({
6992
+ ...chatbotContext,
6993
+ [bodyText?.paramName]: {
6994
+ ...chatbotContext?.[bodyText?.paramName],
6995
+ [bodyText?.paramName]: [],
6996
+ updated: true,
6997
+ },
6998
+ }));
6999
+ dispatch(setPersistedFormValues({ [formKey]: [] }));
6925
7000
  // Notify cross-filter context of deselection
6926
7001
  if (isCascading) {
6927
7002
  crossFilterCtx.onFilterChange(paramName, []);
6928
7003
  }
6929
7004
  }
6930
- }, customPlaceholderAfterSelect: isAllSelected && allOptionsRef.current.length > 0
6931
- ? allOptionsRef.current.length
7005
+ }, customPlaceholderAfterSelect: currentSelectedOptions.length > 0
7006
+ ? currentSelectedOptions.length
6932
7007
  : null }) }));
6933
7008
  };
6934
7009
 
@@ -10058,7 +10133,13 @@ const TabularContent = ({ steps: initialSteps, currentTabValue, children, questi
10058
10133
  };
10059
10134
  }
10060
10135
  }
10061
- if (data.status === "widget") ;
10136
+ if (data.status === "widget") {
10137
+ const widgetItems = isArray$2(data.widget_data) ? data.widget_data : [data.widget_data];
10138
+ widgetItems.forEach((item) => {
10139
+ if (item)
10140
+ newWidgets.push(item);
10141
+ });
10142
+ }
10062
10143
  if (data.status === "content" && data.message) {
10063
10144
  newWidgets.push({ type: "text", response: data.message });
10064
10145
  }
@@ -10073,7 +10154,8 @@ const TabularContent = ({ steps: initialSteps, currentTabValue, children, questi
10073
10154
  setQuestionsStepsMapState(cloneDeep(newQuestionsStepsMap));
10074
10155
  setStepFormDataMapState(cloneDeep(newStepFormDataMap));
10075
10156
  if (newWidgets.length > 0) {
10076
- setWidgetContent((prev) => [...prev, ...newWidgets]);
10157
+ // Replace (not append) to avoid duplicates from real-time widget_chunk dispatches
10158
+ setWidgetContent(newWidgets);
10077
10159
  }
10078
10160
  // If the response contains a new step_form, reset stepFormSubmitted and mark new form as active
10079
10161
  const lastStepFormChunk = [...chunks].reverse().find((c) => c.status === "step_form");