@rh-support/cases 2.6.185 → 2.6.187

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.
Files changed (87) hide show
  1. package/lib/esm/components/case-list/CaseList.d.ts.map +1 -1
  2. package/lib/esm/components/case-list/CaseList.js +85 -38
  3. package/lib/esm/components/case-list/CaseListFilterContext.d.ts.map +1 -1
  4. package/lib/esm/components/case-list/CaseListFilterContext.js +2 -1
  5. package/lib/esm/components/case-list/CaseListFilterHelpers.d.ts +3 -2
  6. package/lib/esm/components/case-list/CaseListFilterHelpers.d.ts.map +1 -1
  7. package/lib/esm/components/case-list/CaseListFilterHelpers.js +19 -6
  8. package/lib/esm/components/case-list/CaseListFilterReducer.d.ts +29 -0
  9. package/lib/esm/components/case-list/CaseListFilterReducer.d.ts.map +1 -1
  10. package/lib/esm/components/case-list/CaseListFilterReducer.js +1 -0
  11. package/lib/esm/components/case-list/case-list-filters/AdditionalFilters.d.ts.map +1 -1
  12. package/lib/esm/components/case-list/case-list-filters/AdditionalFilters.js +5 -0
  13. package/lib/esm/components/case-list/case-list-filters/CaseListFilterChips.d.ts.map +1 -1
  14. package/lib/esm/components/case-list/case-list-filters/CaseListFilterChips.js +5 -1
  15. package/lib/esm/components/case-list/case-list-filters/CaseListFilters.d.ts.map +1 -1
  16. package/lib/esm/components/case-list/case-list-filters/CaseListFilters.js +1 -2
  17. package/lib/esm/components/case-list/case-list-filters/CreatorSsoNameFilterChip.d.ts.map +1 -1
  18. package/lib/esm/components/case-list/case-list-filters/CreatorSsoNameFilterChip.js +3 -0
  19. package/lib/esm/components/case-list/case-list-filters/GroupsFilter.d.ts +11 -1
  20. package/lib/esm/components/case-list/case-list-filters/GroupsFilter.d.ts.map +1 -1
  21. package/lib/esm/components/case-list/case-list-filters/GroupsFilter.js +116 -71
  22. package/lib/esm/components/case-list/case-list-filters/VersionsFilter.d.ts.map +1 -1
  23. package/lib/esm/components/case-list/case-list-filters/VersionsFilter.js +1 -29
  24. package/lib/esm/components/case-list/case-list-table/CaseListTable.d.ts.map +1 -1
  25. package/lib/esm/components/case-list/case-list-table/CaseListTable.js +11 -5
  26. package/lib/esm/components/case-list/case-search/AdvanceSearch.d.ts.map +1 -1
  27. package/lib/esm/components/case-list/case-search/AdvanceSearch.js +1 -1
  28. package/lib/esm/components/case-list/case-search/AdvanceSearchToggleButton.d.ts +8 -0
  29. package/lib/esm/components/case-list/case-search/AdvanceSearchToggleButton.d.ts.map +1 -0
  30. package/lib/esm/components/case-list/case-search/AdvanceSearchToggleButton.js +8 -0
  31. package/lib/esm/components/case-list/case-search/CaseSearch.d.ts.map +1 -1
  32. package/lib/esm/components/case-list/case-search/CaseSearch.js +51 -20
  33. package/lib/esm/components/case-list/case-search/advance-search-modal/AdvanceSearchAccountSection.d.ts +10 -0
  34. package/lib/esm/components/case-list/case-search/advance-search-modal/AdvanceSearchAccountSection.d.ts.map +1 -0
  35. package/lib/esm/components/case-list/case-search/advance-search-modal/AdvanceSearchAccountSection.js +29 -0
  36. package/lib/esm/components/case-list/case-search/advance-search-modal/AdvanceSearchAuditsSection.d.ts +10 -0
  37. package/lib/esm/components/case-list/case-search/advance-search-modal/AdvanceSearchAuditsSection.d.ts.map +1 -0
  38. package/lib/esm/components/case-list/case-search/advance-search-modal/AdvanceSearchAuditsSection.js +16 -0
  39. package/lib/esm/components/case-list/case-search/advance-search-modal/AdvanceSearchCaseSection.d.ts +9 -0
  40. package/lib/esm/components/case-list/case-search/advance-search-modal/AdvanceSearchCaseSection.d.ts.map +1 -0
  41. package/lib/esm/components/case-list/case-search/advance-search-modal/AdvanceSearchCaseSection.js +21 -0
  42. package/lib/esm/components/case-list/case-search/advance-search-modal/AdvanceSearchDateRangeField.d.ts +12 -0
  43. package/lib/esm/components/case-list/case-search/advance-search-modal/AdvanceSearchDateRangeField.d.ts.map +1 -0
  44. package/lib/esm/components/case-list/case-search/advance-search-modal/AdvanceSearchDateRangeField.js +31 -0
  45. package/lib/esm/components/case-list/case-search/advance-search-modal/AdvanceSearchFieldBlock.d.ts +10 -0
  46. package/lib/esm/components/case-list/case-search/advance-search-modal/AdvanceSearchFieldBlock.d.ts.map +1 -0
  47. package/lib/esm/components/case-list/case-search/advance-search-modal/AdvanceSearchFieldBlock.js +10 -0
  48. package/lib/esm/components/case-list/case-search/advance-search-modal/AdvanceSearchModal.d.ts +10 -0
  49. package/lib/esm/components/case-list/case-search/advance-search-modal/AdvanceSearchModal.d.ts.map +1 -0
  50. package/lib/esm/components/case-list/case-search/advance-search-modal/AdvanceSearchModal.js +92 -0
  51. package/lib/esm/components/case-list/case-search/advance-search-modal/AdvanceSearchOwnerSection.d.ts +9 -0
  52. package/lib/esm/components/case-list/case-search/advance-search-modal/AdvanceSearchOwnerSection.d.ts.map +1 -0
  53. package/lib/esm/components/case-list/case-search/advance-search-modal/AdvanceSearchOwnerSection.js +20 -0
  54. package/lib/esm/components/case-list/case-search/advance-search-modal/AdvanceSearchProductSection.d.ts +9 -0
  55. package/lib/esm/components/case-list/case-search/advance-search-modal/AdvanceSearchProductSection.d.ts.map +1 -0
  56. package/lib/esm/components/case-list/case-search/advance-search-modal/AdvanceSearchProductSection.js +28 -0
  57. package/lib/esm/components/case-list/case-search/advance-search-modal/ProductVersionDrilldownSelect.d.ts +9 -0
  58. package/lib/esm/components/case-list/case-search/advance-search-modal/ProductVersionDrilldownSelect.d.ts.map +1 -0
  59. package/lib/esm/components/case-list/case-search/advance-search-modal/ProductVersionDrilldownSelect.js +241 -0
  60. package/lib/esm/components/case-list/case-search/advance-search-modal/SelectableLabelFilter.d.ts +11 -0
  61. package/lib/esm/components/case-list/case-search/advance-search-modal/SelectableLabelFilter.d.ts.map +1 -0
  62. package/lib/esm/components/case-list/case-search/advance-search-modal/SelectableLabelFilter.js +23 -0
  63. package/lib/esm/css/caseList.css +13 -1
  64. package/lib/esm/css/caseSearch.css +114 -0
  65. package/lib/esm/enums/caseSearch.d.ts +1 -0
  66. package/lib/esm/enums/caseSearch.d.ts.map +1 -1
  67. package/lib/esm/enums/caseSearch.js +1 -1
  68. package/lib/esm/hooks/useFilterStateOnLoad.d.ts +1 -1
  69. package/lib/esm/hooks/useFilterStateOnLoad.d.ts.map +1 -1
  70. package/lib/esm/utils/advanceSearchFormMapper.d.ts +11 -0
  71. package/lib/esm/utils/advanceSearchFormMapper.d.ts.map +1 -0
  72. package/lib/esm/utils/advanceSearchFormMapper.js +71 -0
  73. package/lib/esm/utils/advanceSearchUtils.d.ts +24 -0
  74. package/lib/esm/utils/advanceSearchUtils.d.ts.map +1 -0
  75. package/lib/esm/utils/advanceSearchUtils.js +149 -0
  76. package/lib/esm/utils/caseListGraphQLUtils.d.ts.map +1 -1
  77. package/lib/esm/utils/caseListGraphQLUtils.js +55 -19
  78. package/lib/esm/utils/caseListMapper.js +4 -4
  79. package/lib/esm/utils/caseListVariablesBuilder.d.ts +1 -0
  80. package/lib/esm/utils/caseListVariablesBuilder.d.ts.map +1 -1
  81. package/lib/esm/utils/caseListVariablesBuilder.js +240 -34
  82. package/lib/esm/utils/caseSearchUtils.d.ts.map +1 -1
  83. package/lib/esm/utils/caseSearchUtils.js +5 -2
  84. package/lib/esm/utils/constants.d.ts +2 -0
  85. package/lib/esm/utils/constants.d.ts.map +1 -1
  86. package/lib/esm/utils/constants.js +6 -0
  87. package/package.json +7 -8
@@ -1,8 +1,8 @@
1
- import { Button, MenuFooter, MenuToggle, Select, SelectList, SelectOption, TextInputGroup, TextInputGroupMain, TextInputGroupUtilities, } from '@patternfly/react-core';
1
+ import { useApolloClient } from '@apollo/client/react';
2
+ import { Badge, Button, MenuFooter, MenuToggle, Select, SelectList, SelectOption, TextInputGroup, TextInputGroupMain, TextInputGroupUtilities, } from '@patternfly/react-core';
2
3
  import TimesIcon from '@patternfly/react-icons/dist/js/icons/times-icon';
3
- import { GlobalMetadataStateContext } from '@rh-support/react-context';
4
4
  import { ability, resourceActions, resources } from '@rh-support/user-permissions';
5
- import { getDropdownBtnPlaceholder } from '@rh-support/utils';
5
+ import { GET_CASE_GROUP, getDropdownBtnPlaceholder, handleGraphQLCaseGroupsResponse, } from '@rh-support/utils';
6
6
  import isEmpty from 'lodash/isEmpty';
7
7
  import isUndefined from 'lodash/isUndefined';
8
8
  import React, { useContext, useEffect, useMemo, useRef, useState } from 'react';
@@ -12,83 +12,125 @@ import { SolrKeys } from '../../../enums/filters';
12
12
  import { filterNamesMap } from '../../../utils/constants';
13
13
  import { CaseListFilterDispatchContext, CaseListFilterStateContext } from '../CaseListFilterContext';
14
14
  import { updateFilter } from '../CaseListFilterReducer';
15
- export function GroupsFilter() {
15
+ const EMPTY_GROUPS = [];
16
+ export function GroupsFilter({ selectedGroups: controlledSelectedGroups, onGroupsChange, hideLabel = false, idPrefix = 'case-list-group-filter', showSelectionCountBadge = false, placeholder: placeholderProp, } = {}) {
17
+ var _a;
16
18
  const { t } = useTranslation();
17
- const { globalMetadataState: { caseGroups }, } = useContext(GlobalMetadataStateContext);
19
+ const apolloClient = useApolloClient();
18
20
  const { filterInfo } = useContext(CaseListFilterStateContext);
19
21
  const dispatch = useContext(CaseListFilterDispatchContext);
22
+ const isControlled = typeof onGroupsChange === 'function';
23
+ // Prefer the filterInfo array reference in basic/uncontrolled mode so empty selection
24
+ // does not create a new [] each render and re-fire the selectedItems sync effect.
25
+ const selectedGroups = isControlled
26
+ ? controlledSelectedGroups || EMPTY_GROUPS
27
+ : (_a = filterInfo === null || filterInfo === void 0 ? void 0 : filterInfo[SolrKeys.group]) !== null && _a !== void 0 ? _a : EMPTY_GROUPS;
20
28
  const [inputValue, setInputValue] = useState('');
29
+ const [caseGroups, setCaseGroups] = useState([]);
30
+ const [isLoading, setIsLoading] = useState(false);
21
31
  const [focusedItemIndex, setFocusedItemIndex] = useState(null);
22
32
  const [activeItem, setActiveItem] = useState(null);
23
- const list = [
24
- ...(caseGroups.data ? caseGroups === null || caseGroups === void 0 ? void 0 : caseGroups.data.map((group) => ({ value: group.name, key: group.groupNum })) : []),
25
- ];
33
+ useEffect(() => {
34
+ setIsLoading(true);
35
+ apolloClient
36
+ .query({
37
+ query: GET_CASE_GROUP,
38
+ fetchPolicy: 'cache-first',
39
+ })
40
+ .then(({ data }) => {
41
+ var _a, _b, _c, _d;
42
+ const edges = (_d = (_c = (_b = (_a = data === null || data === void 0 ? void 0 : data.salesforce_support_uiapi) === null || _a === void 0 ? void 0 : _a.query) === null || _b === void 0 ? void 0 : _b.SalesforceSupportCaseGroup__c) === null || _c === void 0 ? void 0 : _c.edges) !== null && _d !== void 0 ? _d : [];
43
+ setCaseGroups(handleGraphQLCaseGroupsResponse(edges));
44
+ })
45
+ .catch((err) => {
46
+ console.error('[GroupsFilter] Failed to fetch case groups:', err);
47
+ setCaseGroups([]);
48
+ })
49
+ .finally(() => setIsLoading(false));
50
+ // eslint-disable-next-line react-hooks/exhaustive-deps
51
+ }, []);
52
+ const list = useMemo(() => caseGroups.map((group) => ({ value: group.name, key: group.groupNum })), [caseGroups]);
26
53
  const [selectOptions, setSelectOptions] = useState(list);
27
54
  const canViewManageTab = ability.can(resourceActions.READ, resources.MANAGE);
28
55
  const canViewCaseGroups = ability.can(resourceActions.READ, resources.CASE_GROUPS) && canViewManageTab;
29
56
  const [isOpen, setIsOpen] = useState(false);
30
57
  const [selectedItems, setSelectedItems] = useState({});
31
58
  const textInputRef = useRef();
32
- const onToggleClick = (e) => {
59
+ const applyGroupSelection = (updatedFilterValues) => {
60
+ if (isControlled) {
61
+ onGroupsChange(updatedFilterValues);
62
+ return;
63
+ }
64
+ updateFilter(dispatch, {
65
+ filterKey: SolrKeys.group,
66
+ values: updatedFilterValues,
67
+ });
68
+ };
69
+ const onToggleClick = () => {
33
70
  setIsOpen(!isOpen);
34
71
  };
35
72
  const onSelect = (option) => {
73
+ const optionValue = typeof option === 'string' ? option : option === null || option === void 0 ? void 0 : option.value;
74
+ if (!optionValue || optionValue === 'no results') {
75
+ return;
76
+ }
36
77
  const prevSelectedGroups = Object.keys(selectedItems).filter((item) => selectedItems[item] && item);
37
- if (selectedItems[option.value]) {
38
- setSelectedItems((prevData) => (Object.assign(Object.assign({}, prevData), { [option.value]: !prevData[option.value] })));
39
- const indexOfGroup = prevSelectedGroups.indexOf(option.value);
78
+ if (selectedItems[optionValue]) {
79
+ setSelectedItems((prevData) => (Object.assign(Object.assign({}, prevData), { [optionValue]: !prevData[optionValue] })));
80
+ const indexOfGroup = prevSelectedGroups.indexOf(optionValue);
40
81
  prevSelectedGroups.splice(indexOfGroup, 1);
41
82
  }
42
83
  else {
43
- setSelectedItems((prevData) => (Object.assign(Object.assign({}, prevData), { [option.value]: true })));
44
- prevSelectedGroups.push(option.value);
84
+ setSelectedItems((prevData) => (Object.assign(Object.assign({}, prevData), { [optionValue]: true })));
85
+ prevSelectedGroups.push(optionValue);
45
86
  }
46
- const mapValueToKey = (value) => {
87
+ const updatedFilterValues = prevSelectedGroups
88
+ .map((value) => {
47
89
  const selectedItem = list.find((item) => item.value === value);
48
- return selectedItem;
49
- };
50
- const updatedFilterValues = prevSelectedGroups.map((item) => mapValueToKey(item));
51
- updateFilter(dispatch, {
52
- filterKey: SolrKeys.group,
53
- values: updatedFilterValues,
54
- });
90
+ if (!(selectedItem === null || selectedItem === void 0 ? void 0 : selectedItem.key)) {
91
+ return null;
92
+ }
93
+ return { key: String(selectedItem.key), value: String(selectedItem.value) };
94
+ })
95
+ .filter(Boolean);
96
+ applyGroupSelection(updatedFilterValues);
55
97
  };
56
98
  const handleMenuArrowKeys = (key) => {
57
- let indexToFocus;
58
- if (isOpen) {
59
- if (key === 'ArrowUp') {
60
- // When no index is set or at the first index, focus to the last, otherwise decrement focus index
61
- if (focusedItemIndex === null || focusedItemIndex === 0) {
62
- indexToFocus = (list === null || list === void 0 ? void 0 : list.length) - 1;
63
- }
64
- else {
65
- indexToFocus = focusedItemIndex - 1;
66
- }
99
+ if (!isOpen || !list.length) {
100
+ return;
101
+ }
102
+ let indexToFocus = 0;
103
+ if (key === 'ArrowUp') {
104
+ if (focusedItemIndex === null || focusedItemIndex === 0) {
105
+ indexToFocus = list.length - 1;
67
106
  }
68
- if (key === 'ArrowDown') {
69
- // When no index is set or at the last index, focus to the first, otherwise increment focus index
70
- if (focusedItemIndex === null || focusedItemIndex === (list === null || list === void 0 ? void 0 : list.length) - 1) {
71
- indexToFocus = 0;
72
- }
73
- else {
74
- indexToFocus = focusedItemIndex + 1;
75
- }
107
+ else {
108
+ indexToFocus = focusedItemIndex - 1;
76
109
  }
77
- setFocusedItemIndex(indexToFocus);
78
- const focusedItem = list[indexToFocus];
79
- setActiveItem(`select-multi-typeahead-checkbox-${focusedItem === null || focusedItem === void 0 ? void 0 : focusedItem.value.replace(' ', '-')}`);
110
+ }
111
+ if (key === 'ArrowDown') {
112
+ if (focusedItemIndex === null || focusedItemIndex === list.length - 1) {
113
+ indexToFocus = 0;
114
+ }
115
+ else {
116
+ indexToFocus = focusedItemIndex + 1;
117
+ }
118
+ }
119
+ setFocusedItemIndex(indexToFocus);
120
+ const focusedItem = list[indexToFocus];
121
+ if (focusedItem === null || focusedItem === void 0 ? void 0 : focusedItem.value) {
122
+ setActiveItem(`select-multi-typeahead-checkbox-${String(focusedItem.value).replace(' ', '-')}`);
80
123
  }
81
124
  };
82
125
  const onInputKeyDown = (event) => {
83
- const focusedItem = focusedItemIndex ? list[focusedItemIndex] : list[0];
126
+ const focusedItem = focusedItemIndex !== null ? list[focusedItemIndex] : list[0];
84
127
  switch (event.key) {
85
- // Select the first available option
86
128
  case 'Enter':
87
129
  if (!isOpen) {
88
130
  setIsOpen((prevIsOpen) => !prevIsOpen);
89
131
  }
90
132
  else if (isOpen && (focusedItem === null || focusedItem === void 0 ? void 0 : focusedItem.value) !== 'no results') {
91
- onSelect(focusedItem === null || focusedItem === void 0 ? void 0 : focusedItem.value);
133
+ onSelect(focusedItem);
92
134
  }
93
135
  break;
94
136
  case 'Tab':
@@ -106,36 +148,37 @@ export function GroupsFilter() {
106
148
  const onTextInputChange = (_event, value) => {
107
149
  setInputValue(value);
108
150
  };
109
- const placeholder = getDropdownBtnPlaceholder(t('Select a group'), filterInfo[SolrKeys.group], '', (caseGroups.data || []).length, t('All selected'));
151
+ const defaultEmptyPlaceholder = placeholderProp || t('Select a group');
152
+ const placeholder = showSelectionCountBadge
153
+ ? isLoading
154
+ ? t('Loading...')
155
+ : defaultEmptyPlaceholder
156
+ : getDropdownBtnPlaceholder(isLoading ? t('Loading...') : defaultEmptyPlaceholder, selectedGroups, '', caseGroups.length, t('All selected'));
157
+ const hasSelectedGroups = selectedGroups.length > 0;
110
158
  const onClick = () => {
111
159
  var _a;
112
160
  setInputValue('');
113
161
  setSelectedItems({});
114
- updateFilter(dispatch, {
115
- filterKey: SolrKeys.group,
116
- values: [],
117
- });
162
+ applyGroupSelection([]);
118
163
  (_a = textInputRef === null || textInputRef === void 0 ? void 0 : textInputRef.current) === null || _a === void 0 ? void 0 : _a.focus();
119
164
  };
120
165
  const toggle = (toggleRef) => (React.createElement(MenuToggle, { variant: "typeahead", onClick: onToggleClick, innerRef: toggleRef, isExpanded: isOpen, isFullWidth: true },
121
166
  React.createElement(TextInputGroup, { isPlain: true },
122
- React.createElement(TextInputGroupMain, Object.assign({ value: inputValue, onClick: onToggleClick, onChange: onTextInputChange, onKeyDown: onInputKeyDown, id: "multi-typeahead-select-checkbox-input", autoComplete: "off", innerRef: textInputRef, placeholder: placeholder }, (activeItem && { 'aria-activedescendant': activeItem }), { role: "combobox", isExpanded: isOpen, "aria-controls": "select-multi-typeahead-checkbox-listbox" })),
123
- Object.keys(selectedItems).filter((key) => selectedItems[key] === true).length ? (React.createElement(TextInputGroupUtilities, null,
124
- React.createElement(Button, { icon: React.createElement(TimesIcon, { "aria-hidden": true }), variant: "plain", onClick: onClick, "aria-label": "Clear input value" }))) : (''))));
167
+ React.createElement(TextInputGroupMain, Object.assign({ value: inputValue, onClick: onToggleClick, onChange: onTextInputChange, onKeyDown: onInputKeyDown, id: `${idPrefix}-input`, autoComplete: "off", innerRef: textInputRef, placeholder: placeholder }, (activeItem && { 'aria-activedescendant': activeItem }), { role: "combobox", isExpanded: isOpen, "aria-controls": `${idPrefix}-listbox` })),
168
+ hasSelectedGroups ? (React.createElement(TextInputGroupUtilities, null,
169
+ showSelectionCountBadge && (React.createElement(Badge, { className: "advance-search-dropdown-toggle-badge pf-v6-u-mr-sm" }, t('{{count}} selected', { count: selectedGroups.length }))),
170
+ React.createElement(Button, { icon: React.createElement(TimesIcon, { "aria-hidden": true }), variant: "plain", onClick: onClick, "aria-label": t('Clear input value') }))) : null)));
125
171
  const dropdownOptions = useMemo(() => {
126
172
  return (!isEmpty(selectOptions) ? selectOptions : list).map((option, index) => !isUndefined(option.value) && (React.createElement(SelectOption, { key: option.key, value: option, hasCheckbox: true, isSelected: selectedItems[option.value], isFocused: focusedItemIndex !== null && focusedItemIndex === index, id: `select-multi-typeahead-${option.value.replace(' ', '-')}` }, option.value)));
127
173
  // eslint-disable-next-line react-hooks/exhaustive-deps
128
- }, [selectedItems, caseGroups === null || caseGroups === void 0 ? void 0 : caseGroups.data, selectOptions, focusedItemIndex]);
174
+ }, [selectedItems, caseGroups, selectOptions, focusedItemIndex]);
129
175
  useEffect(() => {
130
176
  let newSelectOptions = list;
131
- // Filter menu items based on the text input value when one exists
132
177
  if (inputValue) {
133
178
  newSelectOptions = list.filter((option) => String(option === null || option === void 0 ? void 0 : option.value).toLowerCase().startsWith(inputValue.toLowerCase()));
134
- // When no options are found after filtering, display 'No results found'
135
179
  if (!newSelectOptions.length) {
136
180
  newSelectOptions = [{ isDisabled: false, children: `No results found` }];
137
181
  }
138
- // Open the menu when the input value changes and the new value is not empty
139
182
  if (!isOpen) {
140
183
  setIsOpen(true);
141
184
  }
@@ -146,27 +189,29 @@ export function GroupsFilter() {
146
189
  // eslint-disable-next-line react-hooks/exhaustive-deps
147
190
  }, [inputValue]);
148
191
  useEffect(() => {
149
- var _a;
150
- if (isEmpty(filterInfo[SolrKeys.group])) {
192
+ if (!inputValue) {
193
+ setSelectOptions(list);
194
+ }
195
+ }, [list, inputValue]);
196
+ useEffect(() => {
197
+ if (isEmpty(selectedGroups)) {
151
198
  setSelectedItems({});
152
199
  }
153
200
  else {
154
- const selectedGroups = (_a = filterInfo[SolrKeys.group]) === null || _a === void 0 ? void 0 : _a.reduce((selection, group) => {
201
+ const nextSelectedItems = selectedGroups.reduce((selection, group) => {
155
202
  selection[group === null || group === void 0 ? void 0 : group.value] = true;
156
203
  return selection;
157
204
  }, {});
158
- setSelectedItems(selectedGroups);
205
+ setSelectedItems(nextSelectedItems);
159
206
  }
160
- // eslint-disable-next-line react-hooks/exhaustive-deps
161
- }, [filterInfo[SolrKeys.group]]);
162
- return (React.createElement("div", { className: "group-filter" },
163
- React.createElement("label", { htmlFor: "case-list-group-filter", className: "pf-v6-u-mb-sm group-filter-label" }, t(filterNamesMap[SolrKeys.group])),
207
+ }, [selectedGroups]);
208
+ return (React.createElement("div", { className: "group-filter", "data-testid": "groups-filter" },
209
+ !hideLabel && (React.createElement("label", { htmlFor: idPrefix, className: "pf-v6-u-mb-sm group-filter-label" }, t(filterNamesMap[SolrKeys.group]))),
164
210
  React.createElement("div", { className: "pf-v6-c-select" },
165
- React.createElement(Select, { shouldFocusToggleOnSelect: true, shouldPreventScrollOnItemFocus: true, "data-tracking-id": "groups-filter", id: "case-list-group-filter", title: t(filterNamesMap[SolrKeys.group]), isOpen: isOpen, selected: selectedItems, onSelect: (_e, v) => onSelect(v), onOpenChange: (nextOpen) => setIsOpen(nextOpen), popperProps: { direction: 'down', enableFlip: false }, toggle: toggle, isScrollable: true },
211
+ React.createElement(Select, { shouldFocusToggleOnSelect: true, shouldPreventScrollOnItemFocus: true, "data-tracking-id": "groups-filter", id: idPrefix, title: t(filterNamesMap[SolrKeys.group]), isOpen: isOpen, selected: selectedItems, onSelect: (_e, v) => onSelect(v), onOpenChange: (nextOpen) => setIsOpen(nextOpen), popperProps: { direction: 'down', enableFlip: false }, toggle: toggle, isScrollable: true },
166
212
  React.createElement(SelectList, null,
167
213
  dropdownOptions,
168
- canViewCaseGroups && (React.createElement(React.Fragment, null,
169
- React.createElement(MenuFooter, { className: "group-filter-manage-groups-footer" },
170
- React.createElement(Link, { className: "cta cta-link", to: "/manage/groups" },
171
- React.createElement(Trans, null, "Manage groups"))))))))));
214
+ canViewCaseGroups && (React.createElement(MenuFooter, { className: "group-filter-manage-groups-footer" },
215
+ React.createElement(Link, { className: "cta cta-link", to: "/manage/groups" },
216
+ React.createElement(Trans, null, "Manage groups")))))))));
172
217
  }
@@ -1 +1 @@
1
- {"version":3,"file":"VersionsFilter.d.ts","sourceRoot":"","sources":["../../../../../src/components/case-list/case-list-filters/VersionsFilter.tsx"],"names":[],"mappings":"AAkBA,OAAO,KAA2D,MAAM,OAAO,CAAC;AAKhF,OAAO,EAAE,cAAc,EAAgB,MAAM,0BAA0B,CAAC;AAgCxE,UAAU,MAAM;IACZ,WAAW,EAAE,cAAc,CAAC;CAC/B;AAED,wBAAgB,cAAc,CAAC,EAAE,WAAW,EAAE,EAAE,MAAM,qBAiQrD"}
1
+ {"version":3,"file":"VersionsFilter.d.ts","sourceRoot":"","sources":["../../../../../src/components/case-list/case-list-filters/VersionsFilter.tsx"],"names":[],"mappings":"AAkBA,OAAO,KAA2D,MAAM,OAAO,CAAC;AAKhF,OAAO,EAAE,cAAc,EAAgB,MAAM,0BAA0B,CAAC;AAExE,UAAU,MAAM;IACZ,WAAW,EAAE,cAAc,CAAC;CAC/B;AAED,wBAAgB,cAAc,CAAC,EAAE,WAAW,EAAE,EAAE,MAAM,qBAiQrD"}
@@ -3,41 +3,13 @@ import { Button, MenuToggle, Select, SelectList, SelectOption, TextInputGroup, T
3
3
  import TimesIcon from '@patternfly/react-icons/dist/js/icons/times-icon';
4
4
  import { useSelectKeyboardNavigator } from '@rh-support/components';
5
5
  import { GlobalMetadataStateContext } from '@rh-support/react-context';
6
- import { GET_PRODUCTS, handleGraphQLVersionsResponse } from '@rh-support/utils';
6
+ import { compareVersions, GET_PRODUCTS, handleGraphQLVersionsResponse } from '@rh-support/utils';
7
7
  import isEmpty from 'lodash/isEmpty';
8
8
  import React, { useContext, useEffect, useMemo, useRef, useState } from 'react';
9
9
  import { useTranslation } from 'react-i18next';
10
10
  import { SolrKeys, SolrPivotKeys } from '../../../enums/filters';
11
11
  import { CaseListFilterDispatchContext, CaseListFilterStateContext } from '../CaseListFilterContext';
12
12
  import { updateFilter } from '../CaseListFilterReducer';
13
- //split version into parts
14
- function parseVersionIntoParts(version) {
15
- //keep unknown version at last
16
- if (version === 'Unknown')
17
- return [Infinity];
18
- //split dots and spaces
19
- return version.split(/[.\s]/).map((p) => (isNaN(Number(p)) ? p : Number(p)));
20
- }
21
- function compareVersions(versionA, versionB) {
22
- var _a, _b;
23
- const pA = parseVersionIntoParts(versionA), pB = parseVersionIntoParts(versionB);
24
- //compare each part
25
- for (let i = 0; i < Math.max(pA.length, pB.length); i++) {
26
- const a = (_a = pA[i]) !== null && _a !== void 0 ? _a : 0, b = (_b = pB[i]) !== null && _b !== void 0 ? _b : 0; //undefined as 0
27
- if (a == b)
28
- continue;
29
- if (typeof a === 'number' && typeof b === 'number')
30
- return a - b;
31
- if (typeof a === 'string' && typeof b === 'string')
32
- return a.localeCompare(b);
33
- //one is string and other is number => string takes precendence
34
- if (typeof a === 'string')
35
- return -1;
36
- if (typeof b === 'string')
37
- return 1;
38
- }
39
- return 0;
40
- }
41
13
  export function VersionsFilter({ productInfo }) {
42
14
  const { t } = useTranslation();
43
15
  const { filterInfo } = useContext(CaseListFilterStateContext);
@@ -1 +1 @@
1
- {"version":3,"file":"CaseListTable.d.ts","sourceRoot":"","sources":["../../../../../src/components/case-list/case-list-table/CaseListTable.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,+CAA+C,CAAC;AAuB3E,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AACzD,OAAO,EAAE,QAAQ,EAAE,MAAM,8BAA8B,CAAC;AAQxD,OAAO,KAAkD,MAAM,OAAO,CAAC;AAKvE,OAAO,EAAE,iBAAiB,EAAyB,MAAM,0BAA0B,CAAC;AAEpF,OAAO,EAAgB,SAAS,EAAyC,MAAM,0BAA0B,CAAC;AA4B1G,UAAU,MAAM;IACZ,QAAQ,EAAE,aAAa,CAAC,iBAAiB,CAAC,CAAC;IAC3C,UAAU,EAAE,UAAU,EAAE,CAAC;IACzB,kBAAkB,EAAE,QAAQ,CAAC;IAC7B,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,qBAAqB,EAAE,OAAO,CAAC;IAC/B,QAAQ,EAAE,OAAO,CAAC;IAClB,WAAW,EAAE,OAAO,CAAC;IACrB,aAAa,EAAE,OAAO,CAAC;IACvB,aAAa,EAAE,OAAO,CAAC;IACvB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,eAAe,EAAE,MAAM,IAAI,CAAC;IAC5B,WAAW,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,OAAO,GAAG,IAAI,KAAK,IAAI,CAAC;CACjD;AAsBD,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,qBAunB1C"}
1
+ {"version":3,"file":"CaseListTable.d.ts","sourceRoot":"","sources":["../../../../../src/components/case-list/case-list-table/CaseListTable.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,+CAA+C,CAAC;AAsB3E,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AACzD,OAAO,EAAE,QAAQ,EAAE,MAAM,8BAA8B,CAAC;AAQxD,OAAO,KAAkD,MAAM,OAAO,CAAC;AAKvE,OAAO,EAAE,iBAAiB,EAAyB,MAAM,0BAA0B,CAAC;AAGpF,OAAO,EAAgB,SAAS,EAAyC,MAAM,0BAA0B,CAAC;AA4B1G,UAAU,MAAM;IACZ,QAAQ,EAAE,aAAa,CAAC,iBAAiB,CAAC,CAAC;IAC3C,UAAU,EAAE,UAAU,EAAE,CAAC;IACzB,kBAAkB,EAAE,QAAQ,CAAC;IAC7B,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,qBAAqB,EAAE,OAAO,CAAC;IAC/B,QAAQ,EAAE,OAAO,CAAC;IAClB,WAAW,EAAE,OAAO,CAAC;IACrB,aAAa,EAAE,OAAO,CAAC;IACvB,aAAa,EAAE,OAAO,CAAC;IACvB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,eAAe,EAAE,MAAM,IAAI,CAAC;IAC5B,WAAW,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,OAAO,GAAG,IAAI,KAAK,IAAI,CAAC;CACjD;AAsBD,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,qBA0oB1C"}
@@ -1,5 +1,4 @@
1
1
  import { Alert, AlertVariant, Bullseye, Button, EmptyState, EmptyStateBody, EmptyStateFooter, EmptyStateVariant, Spinner, } from '@patternfly/react-core';
2
- import RedoAltIcon from '@patternfly/react-icons/dist/js/icons/redo-alt-icon';
3
2
  import SearchIcon from '@patternfly/react-icons/dist/js/icons/search-icon';
4
3
  import { Table, TableVariant, Tbody, Td, Th, Thead, Tr, Visibility } from '@patternfly/react-table';
5
4
  import { TableComponent } from '@rh-support/components';
@@ -15,6 +14,7 @@ import React, { useContext, useEffect, useRef, useState } from 'react';
15
14
  import { Trans, useTranslation } from 'react-i18next';
16
15
  import { Link } from 'react-router-dom';
17
16
  import { CaseListColumnIds } from '../../../enums/case';
17
+ import { mapSfdcStatusToPortalStatus } from '../../../utils/statusUtils';
18
18
  import { CaseListFilterDispatchContext, CaseListFilterStateContext } from '../CaseListFilterContext';
19
19
  import { clearFilters, resetFilterToDefaultState, updateSort } from '../CaseListFilterReducer';
20
20
  import SeverityLabel from './SeverityLabel';
@@ -53,7 +53,7 @@ export function CaseListTable(props) {
53
53
  const { globalMetadataState: { hydraUserPreferences, loggedInUserRights }, } = useGlobalStateContext();
54
54
  const dispatch = useContext(CaseListFilterDispatchContext);
55
55
  const dispatchToGlobalMetadataReducer = useContext(GlobalMetadataDispatchContext);
56
- const { filterInfo, filterQueryInfo } = useContext(CaseListFilterStateContext);
56
+ const { filterInfo, filterQueryInfo, paginationInfo } = useContext(CaseListFilterStateContext);
57
57
  const currentFilterLength = flatMap(filterInfo).length;
58
58
  const showingFilter = currentFilterLength > 0;
59
59
  const hasSearchQuery = !((filterQueryInfo === null || filterQueryInfo === void 0 ? void 0 : filterQueryInfo.queryString) === '');
@@ -269,7 +269,7 @@ export function CaseListTable(props) {
269
269
  ? formatDate(row.case_last_public_update_date)
270
270
  : '',
271
271
  case_severity: row.case_severity ? row.case_severity : '',
272
- case_status: row.case_status,
272
+ case_status: mapSfdcStatusToPortalStatus(row.case_status),
273
273
  case_createdDate: formatDate(row.case_createdDate),
274
274
  case_accountNumber: row.case_accountNumber,
275
275
  case_alternate_id: row.case_alternate_id ? row.case_alternate_id : '',
@@ -404,7 +404,9 @@ export function CaseListTable(props) {
404
404
  visibleCaseListColumns.map((col) => (React.createElement(Td, { key: `skeleton-${col.id}` },
405
405
  React.createElement("span", { className: "skeleton-bar" }))))))))))),
406
406
  props.loadMoreError && props.loadMoreRetryCount <= 1 && (React.createElement("div", { className: "infinite-scroll-footer-message" },
407
- React.createElement(Button, { className: "infinite-scroll-retry-btn", variant: "secondary", onClick: props.onRetryLoadMore, icon: React.createElement(RedoAltIcon, null) },
407
+ React.createElement(Button, { className: "infinite-scroll-retry-btn", variant: "secondary", onClick: props.onRetryLoadMore, icon: React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", width: "14", height: "14", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round" },
408
+ React.createElement("polyline", { points: "23 4 23 10 17 10" }),
409
+ React.createElement("path", { d: "M20.49 15a9 9 0 1 1-2.12-9.36L23 10" })) },
408
410
  React.createElement(Trans, null, "try loading again")))),
409
411
  props.loadMoreError && props.loadMoreRetryCount > 1 && (React.createElement("div", { className: "infinite-scroll-footer-message" },
410
412
  React.createElement(Alert, { className: "infinite-scroll-alert pf-v6-u-font-weight-bold", variant: AlertVariant.danger, isInline: true, isPlain: true, title: React.createElement("span", null,
@@ -413,6 +415,10 @@ export function CaseListTable(props) {
413
415
  React.createElement(Button, { variant: "link", isInline: true, onClick: props.onRetryLoadMore },
414
416
  React.createElement(Trans, null, "try again")),
415
417
  ".") }))),
416
- !props.hasNextPage && !props.isLoadingMore && !props.loadMoreError && caseListData.length > 0 && (React.createElement("div", { className: "infinite-scroll-footer-message infinite-scroll-footer-text pf-v6-u-font-weight-bold pf-v6-u-color-200" },
418
+ !props.hasNextPage &&
419
+ !props.isLoadingMore &&
420
+ !props.loadMoreError &&
421
+ caseListData.length > 0 &&
422
+ getItemCount() > ((paginationInfo === null || paginationInfo === void 0 ? void 0 : paginationInfo.pageSize) || 10) && (React.createElement("div", { className: "infinite-scroll-footer-message infinite-scroll-footer-text pf-v6-u-font-weight-bold pf-v6-u-color-200" },
417
423
  React.createElement(Trans, null, "No more cases to load"))))));
418
424
  }
@@ -1 +1 @@
1
- {"version":3,"file":"AdvanceSearch.d.ts","sourceRoot":"","sources":["../../../../../src/components/case-list/case-search/AdvanceSearch.tsx"],"names":[],"mappings":"AAoBA,OAAO,KAAkD,MAAM,OAAO,CAAC;AAGvE,OAAO,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAIhE,UAAU,MAAM;IACZ,iBAAiB,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7C,kBAAkB,CAAC,EAAE,CAAC,OAAO,EAAE,mBAAmB,KAAK,IAAI,CAAC;IAC5D,aAAa,CAAC,EAAE,MAAM,IAAI,CAAC;IAC3B,cAAc,EAAE,CAAC,IAAI,EAAE,mBAAmB,EAAE,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC;IACzE,0BAA0B,EAAE,CAAC,UAAU,EAAE,OAAO,KAAK,IAAI,CAAC;IAC1D,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC9B;AAOD,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,qBA2S1C"}
1
+ {"version":3,"file":"AdvanceSearch.d.ts","sourceRoot":"","sources":["../../../../../src/components/case-list/case-search/AdvanceSearch.tsx"],"names":[],"mappings":"AAoBA,OAAO,KAAkD,MAAM,OAAO,CAAC;AAGvE,OAAO,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAIhE,UAAU,MAAM;IACZ,iBAAiB,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7C,kBAAkB,CAAC,EAAE,CAAC,OAAO,EAAE,mBAAmB,KAAK,IAAI,CAAC;IAC5D,aAAa,CAAC,EAAE,MAAM,IAAI,CAAC;IAC3B,cAAc,EAAE,CAAC,IAAI,EAAE,mBAAmB,EAAE,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC;IACzE,0BAA0B,EAAE,CAAC,UAAU,EAAE,OAAO,KAAK,IAAI,CAAC;IAC1D,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC9B;AAOD,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,qBA0S1C"}
@@ -176,7 +176,7 @@ export function AdvanceSearch(props) {
176
176
  });
177
177
  const toggle = (toggleRef) => (React.createElement(MenuToggle, { variant: "typeahead", onClick: () => setIsOpen((open) => !open), onKeyDown: onInputKeyDown, innerRef: toggleRef, isExpanded: isOpen, isFullWidth: true },
178
178
  React.createElement(TextInputGroup, { isPlain: true },
179
- React.createElement(TextInputGroupMain, { value: inputString, onChange: (event, value) => onQueryStringChange(value), onClick: () => setIsOpen((open) => !open), onFocus: () => setIsOpen(true), ref: searchInputRef, placeholder: t('i18nEnterSolrQuery', 'Enter SOLR query, for example: severity:"1 (Urgent)" and status:"Waiting on Customer"'), className: "pf-v6-u-pr-2xl", type: "text", "aria-invalid": isQueryInValid ? true : false, autoComplete: "off", id: "advance-search-typeahead", "aria-label": t('Enter search query'), "aria-describedby": "advance-query-error-helper" }),
179
+ React.createElement(TextInputGroupMain, { value: inputString, onChange: (event, value) => onQueryStringChange(value), onClick: () => setIsOpen((open) => !open), ref: searchInputRef, placeholder: t('i18nEnterSolrQuery', 'Enter SOLR query, for example: severity:"1 (Urgent)" and status:"Waiting on Customer"'), className: "pf-v6-u-pr-2xl", type: "text", "aria-invalid": isQueryInValid ? true : false, autoComplete: "off", id: "advance-search-typeahead", "aria-label": t('Enter search query'), "aria-describedby": "advance-query-error-helper" }),
180
180
  inputString && (React.createElement(TextInputGroupUtilities, null,
181
181
  React.createElement(Button, { icon: inputString && isParsingSuccessful ? (React.createElement(Flex, { justifyContent: { default: 'justifyContentSpaceBetween' } },
182
182
  React.createElement(FlexItem, null,
@@ -0,0 +1,8 @@
1
+ import React from 'react';
2
+ interface IProps {
3
+ appliedFilterCount: number;
4
+ onClick: () => void;
5
+ }
6
+ export declare function AdvanceSearchToggleButton({ appliedFilterCount, onClick }: IProps): React.JSX.Element;
7
+ export {};
8
+ //# sourceMappingURL=AdvanceSearchToggleButton.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AdvanceSearchToggleButton.d.ts","sourceRoot":"","sources":["../../../../../src/components/case-list/case-search/AdvanceSearchToggleButton.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,MAAM,OAAO,CAAC;AAG1B,UAAU,MAAM;IACZ,kBAAkB,EAAE,MAAM,CAAC;IAC3B,OAAO,EAAE,MAAM,IAAI,CAAC;CACvB;AAED,wBAAgB,yBAAyB,CAAC,EAAE,kBAAkB,EAAE,OAAO,EAAE,EAAE,MAAM,qBAehF"}
@@ -0,0 +1,8 @@
1
+ import { Button } from '@patternfly/react-core';
2
+ import AngleDownIcon from '@patternfly/react-icons/dist/js/icons/angle-down-icon';
3
+ import React from 'react';
4
+ import { Trans } from 'react-i18next';
5
+ export function AdvanceSearchToggleButton({ appliedFilterCount, onClick }) {
6
+ return (React.createElement(Button, { type: "button", variant: "secondary", onClick: onClick, className: "advance-search-toggle-btn secondary-button-pill", icon: React.createElement(AngleDownIcon, { "aria-hidden": true }), iconPosition: "end", countOptions: appliedFilterCount > 0 ? { count: appliedFilterCount } : undefined, "data-tracking-id": "case-list-adv-toggle-button" },
7
+ React.createElement(Trans, null, "Advanced Search")));
8
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"CaseSearch.d.ts","sourceRoot":"","sources":["../../../../../src/components/case-list/case-search/CaseSearch.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAuD,MAAM,OAAO,CAAC;AAkB5E,UAAU,MAAM;IACZ,sBAAsB,CAAC,EAAE,MAAM,CAAC;CACnC;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,qBAmMvC"}
1
+ {"version":3,"file":"CaseSearch.d.ts","sourceRoot":"","sources":["../../../../../src/components/case-list/case-search/CaseSearch.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAgE,MAAM,OAAO,CAAC;AA8BrF,UAAU,MAAM;IACZ,sBAAsB,CAAC,EAAE,MAAM,CAAC;CACnC;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,qBA4OvC"}
@@ -2,14 +2,18 @@ import { Button, SearchInput } from '@patternfly/react-core';
2
2
  import { GlobalMetadataStateContext } from '@rh-support/react-context';
3
3
  import { AbilityContext, CaseListFields, resourceActions, resources } from '@rh-support/user-permissions';
4
4
  import isEmpty from 'lodash/isEmpty';
5
- import React, { useCallback, useContext, useEffect, useState } from 'react';
5
+ import React, { useCallback, useContext, useEffect, useMemo, useState } from 'react';
6
6
  import { Trans, useTranslation } from 'react-i18next';
7
7
  import { CaseSearchQueryType } from '../../../enums/caseSearch';
8
+ import { createCaseListFilterStateFromAdvanceSearchForm, deriveSearchQueryType, } from '../../../utils/advanceSearchFormMapper';
9
+ import { getAdvanceSearchAppliedFilterCount } from '../../../utils/advanceSearchUtils';
8
10
  import { createFilterStateFromAdvancedQuery, createUserFriendlyQueryFromFilterStateAdvancedSearch, } from '../../../utils/caseSearchUtils';
9
11
  // import { useCaseListStateContext } from '../CaseListContext';
10
12
  import { CaseListFilterDispatchContext, CaseListFilterStateContext, initialPaginationInfo, } from '../CaseListFilterContext';
11
- import { initialFilterInfo, updateFilterQuery, updateFilterState } from '../CaseListFilterReducer';
13
+ import { initialFilterInfo, updateFilterQuery, updateFilterState, } from '../CaseListFilterReducer';
14
+ import { AdvanceSearchModal } from './advance-search-modal/AdvanceSearchModal';
12
15
  import { AdvanceSearch } from './AdvanceSearch';
16
+ import { AdvanceSearchToggleButton } from './AdvanceSearchToggleButton';
13
17
  import { BookmarkedSearchesSelector } from './BookmarkedSearchesSelector';
14
18
  export function CaseSearch(props) {
15
19
  const { globalMetadataState } = useContext(GlobalMetadataStateContext);
@@ -20,26 +24,29 @@ export function CaseSearch(props) {
20
24
  const { filterQueryInfo } = filterState;
21
25
  const [searchVal, setSearchVal] = useState(filterQueryInfo.queryString);
22
26
  const [isAdvancedSearchValid, setIsAdvancedSearchValid] = useState(true);
27
+ const [isAdvanceSearchModalOpen, setIsAdvanceSearchModalOpen] = useState(false);
23
28
  const dispatch = useContext(CaseListFilterDispatchContext);
24
29
  // const { isFetching } = useCaseListStateContext();
25
30
  const getType = useCallback(() => (filterQueryInfo === null || filterQueryInfo === void 0 ? void 0 : filterQueryInfo.type) || CaseSearchQueryType.BASIC, [filterQueryInfo === null || filterQueryInfo === void 0 ? void 0 : filterQueryInfo.type]);
26
- // on queryString and parsedQuery change need to update search
31
+ // Keep the keyword search input in sync with queryString only (not modal filter parsedQuery).
27
32
  useEffect(() => {
28
- if (getType() === CaseSearchQueryType.ADVANCED) {
29
- setSearchVal(filterQueryInfo === null || filterQueryInfo === void 0 ? void 0 : filterQueryInfo.parsedQuery);
30
- }
31
- else {
32
- const query = filterQueryInfo.queryString;
33
- setSearchVal(query.endsWith('*') ? query.slice(0, -1) : query);
34
- }
35
- }, [filterQueryInfo, getType]);
33
+ const query = filterQueryInfo.queryString;
34
+ setSearchVal(query.endsWith('*') ? query.slice(0, -1) : query);
35
+ }, [filterQueryInfo === null || filterQueryInfo === void 0 ? void 0 : filterQueryInfo.queryString]);
36
36
  const onSearchValChange = (value) => {
37
37
  setSearchVal(value === null || value === void 0 ? void 0 : value.trim());
38
38
  };
39
39
  const clearSearchVal = () => {
40
40
  setSearchVal('');
41
- (filterQueryInfo === null || filterQueryInfo === void 0 ? void 0 : filterQueryInfo.queryString) &&
42
- updateFilterQuery(dispatch, { type: getType(), queryString: '', parsedQuery: '' });
41
+ if (!(filterQueryInfo === null || filterQueryInfo === void 0 ? void 0 : filterQueryInfo.queryString)) {
42
+ return;
43
+ }
44
+ const nextFilterQueryInfo = {
45
+ queryString: '',
46
+ parsedQuery: filterQueryInfo.parsedQuery || '',
47
+ type: deriveSearchQueryType(Object.assign(Object.assign({}, filterState), { filterQueryInfo: Object.assign(Object.assign({}, filterQueryInfo), { queryString: '' }) })),
48
+ };
49
+ updateFilterQuery(dispatch, nextFilterQueryInfo);
43
50
  };
44
51
  const clearAdvancedSearchVal = () => {
45
52
  setSearchVal('');
@@ -48,11 +55,21 @@ export function CaseSearch(props) {
48
55
  queryString: '',
49
56
  parsedQuery: '',
50
57
  type: CaseSearchQueryType.ADVANCED,
51
- }, paginationInfo: initialPaginationInfo }));
58
+ }, paginationInfo: initialPaginationInfo, advanceSearchDateRanges: undefined }));
52
59
  };
53
- const onCaseSearch = (parsedQuery = '', queryString = searchVal) => {
54
- const finalQueryString = `${queryString.trim()}*`;
55
- updateFilterQuery(dispatch, { type: getType(), queryString: finalQueryString, parsedQuery });
60
+ const onCaseSearch = (parsedQuery = filterQueryInfo.parsedQuery || '', queryString = searchVal) => {
61
+ const trimmedQuery = queryString.trim();
62
+ const finalQueryString = trimmedQuery ? `${trimmedQuery}*` : '';
63
+ const nextFilterState = Object.assign(Object.assign({}, filterState), { filterQueryInfo: {
64
+ queryString: finalQueryString,
65
+ parsedQuery,
66
+ type: filterQueryInfo.type,
67
+ } });
68
+ updateFilterQuery(dispatch, {
69
+ queryString: finalQueryString,
70
+ parsedQuery,
71
+ type: deriveSearchQueryType(nextFilterState),
72
+ });
56
73
  };
57
74
  const onCaseSearchAdvanced = (type, parsedQuery = '', queryStringInputBox = searchVal) => {
58
75
  const newFilterState = createFilterStateFromAdvancedQuery(parsedQuery.replace(/ and /g, ' AND ').replace(/ or /g, ' OR ').replace('Bug OR defect', 'Bug or defect'), globalMetadataState, filterState, queryStringInputBox, type);
@@ -90,15 +107,29 @@ export function CaseSearch(props) {
90
107
  };
91
108
  const handleSubmit = (ev) => {
92
109
  ev.preventDefault();
93
- // For advance search submit should only happen on btn click or ctrl+enter which will be handled manually
94
- getType() === CaseSearchQueryType.BASIC && onCaseSearch();
110
+ onCaseSearch();
111
+ };
112
+ const openAdvanceSearchModal = () => {
113
+ setIsAdvanceSearchModalOpen(true);
114
+ };
115
+ const closeAdvanceSearchModal = () => {
116
+ setIsAdvanceSearchModalOpen(false);
117
+ };
118
+ const onAdvanceSearchModalSubmit = (formState) => {
119
+ const newFilterState = createCaseListFilterStateFromAdvanceSearchForm(formState, filterState);
120
+ updateFilterState(dispatch, newFilterState);
121
+ closeAdvanceSearchModal();
95
122
  };
123
+ const appliedAdvanceSearchFilterCount = useMemo(() => getAdvanceSearchAppliedFilterCount(filterState), [filterState]);
96
124
  const renderBasicSearch = () => {
97
125
  return (React.createElement(React.Fragment, null,
98
126
  React.createElement("div", { className: "case-search-input-container" },
99
127
  React.createElement(SearchInput, { className: "pf-v6-u-w-100 case-search-input", placeholder: t('Search by keyword or case ID'), value: searchVal === null || searchVal === void 0 ? void 0 : searchVal.trim(), "data-tracking-id": "search-cases-text-input", id: "case-search-basic", "aria-label": t('Search by keyword or case ID'), onChange: (_event, val) => onSearchValChange(val), onClear: clearSearchVal }),
100
128
  React.createElement(Button, { variant: "primary", type: "submit", className: "search-btn", "data-tracking-id": "case-list-search-button", isDisabled: isSearchButtonDisabled },
101
- React.createElement(Trans, null, "Search")))));
129
+ React.createElement(Trans, null, "Search")),
130
+ canUseAdvancedSearch && (React.createElement("div", { className: "advance-search-panel-container" },
131
+ React.createElement(AdvanceSearchToggleButton, { appliedFilterCount: appliedAdvanceSearchFilterCount, onClick: openAdvanceSearchModal }),
132
+ React.createElement(AdvanceSearchModal, { isOpen: isAdvanceSearchModalOpen, onClose: closeAdvanceSearchModal, onSearch: onAdvanceSearchModalSubmit }))))));
102
133
  };
103
134
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
104
135
  const renderAdvanceSearch = () => {
@@ -0,0 +1,10 @@
1
+ import React from 'react';
2
+ import { IAdvanceSearchFormState } from '../../CaseListFilterReducer';
3
+ interface IProps {
4
+ formState: IAdvanceSearchFormState;
5
+ onChange: (updates: Partial<IAdvanceSearchFormState>) => void;
6
+ canReadAccounts: boolean;
7
+ }
8
+ export declare function AdvanceSearchAccountSection({ formState, onChange, canReadAccounts }: IProps): React.JSX.Element;
9
+ export {};
10
+ //# sourceMappingURL=AdvanceSearchAccountSection.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AdvanceSearchAccountSection.d.ts","sourceRoot":"","sources":["../../../../../../src/components/case-list/case-search/advance-search-modal/AdvanceSearchAccountSection.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAkB,MAAM,OAAO,CAAC;AAGvC,OAAO,EAAE,uBAAuB,EAAE,MAAM,6BAA6B,CAAC;AAGtE,UAAU,MAAM;IACZ,SAAS,EAAE,uBAAuB,CAAC;IACnC,QAAQ,EAAE,CAAC,OAAO,EAAE,OAAO,CAAC,uBAAuB,CAAC,KAAK,IAAI,CAAC;IAC9D,eAAe,EAAE,OAAO,CAAC;CAC5B;AAED,wBAAgB,2BAA2B,CAAC,EAAE,SAAS,EAAE,QAAQ,EAAE,eAAe,EAAE,EAAE,MAAM,qBAkE3F"}
@@ -0,0 +1,29 @@
1
+ import { Button, Stack, TextInput } from '@patternfly/react-core';
2
+ import TimesIcon from '@patternfly/react-icons/dist/js/icons/times-icon';
3
+ import { AccountSelectorInternal } from '@rh-support/react-context';
4
+ import React, { useMemo } from 'react';
5
+ import { Trans, useTranslation } from 'react-i18next';
6
+ import { AdvanceSearchFieldBlock } from './AdvanceSearchFieldBlock';
7
+ export function AdvanceSearchAccountSection({ formState, onChange, canReadAccounts }) {
8
+ const { t } = useTranslation();
9
+ const selectedAccounts = useMemo(() => formState.accountNumbers
10
+ .filter((item) => !Array.isArray(item.key))
11
+ .map((item) => ({
12
+ name: item.value,
13
+ accountNumber: item.key,
14
+ })), [formState.accountNumbers]);
15
+ const onAccountsChange = (selected) => {
16
+ onChange({
17
+ accountNumbers: selected.map((account) => ({
18
+ key: account.accountNumber,
19
+ value: account.name,
20
+ })),
21
+ });
22
+ };
23
+ return (React.createElement(Stack, null,
24
+ canReadAccounts && (React.createElement(AdvanceSearchFieldBlock, { label: React.createElement(Trans, null, "Select account number or name"), headerActions: selectedAccounts.length > 0 ? (React.createElement(Button, { variant: "plain", icon: React.createElement(TimesIcon, { "aria-hidden": true }), "aria-label": t('Clear account selection'), onClick: () => onChange({ accountNumbers: [] }), "data-tracking-id": "advance-search-accounts-clear", className: "pf-v6-u-p-0" })) : undefined },
25
+ React.createElement("div", { "data-tracking-id": "advance-search-accounts-filter" },
26
+ React.createElement(AccountSelectorInternal, { label: t('Account number or name'), selectedAccounts: selectedAccounts, multiple: true, suggestBookmarkAccounts: false, showSelectionCountBadge: true, placeholder: t('Account number or name'), onSelect: onAccountsChange })))),
27
+ React.createElement(AdvanceSearchFieldBlock, { label: React.createElement(Trans, null, "Personal reference number") },
28
+ React.createElement(TextInput, { id: "advance-search-personal-ref", type: "text", value: formState.personalReferenceNumber, onChange: (_event, value) => onChange({ personalReferenceNumber: value }), "aria-label": t('Personal reference number'), placeholder: t('Personal reference number') }))));
29
+ }