@rh-support/troubleshoot 2.2.185 → 2.2.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.
@@ -1 +1 @@
1
- {"version":3,"file":"CaseDetailsTabs.d.ts","sourceRoot":"","sources":["../../../../src/components/CaseEditView/CaseDetailsTabs.tsx"],"names":[],"mappings":"AAeA,OAAO,KAAiD,MAAM,OAAO,CAAC;AAEtE,OAAO,EAAE,mBAAmB,EAAa,MAAM,kBAAkB,CAAC;AAyBlE,UAAU,MAAM;IACZ,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,mBAAmB,CAAC;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,KAAK,CAAC,gBAAgB,CAAC,cAAc,CAAC,CAAC;CACnD;AACD,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,qBAgO5C"}
1
+ {"version":3,"file":"CaseDetailsTabs.d.ts","sourceRoot":"","sources":["../../../../src/components/CaseEditView/CaseDetailsTabs.tsx"],"names":[],"mappings":"AAeA,OAAO,KAAiD,MAAM,OAAO,CAAC;AAEtE,OAAO,EAAE,mBAAmB,EAAa,MAAM,kBAAkB,CAAC;AAyBlE,UAAU,MAAM;IACZ,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,mBAAmB,CAAC;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,KAAK,CAAC,gBAAgB,CAAC,cAAc,CAAC,CAAC;CACnD;AACD,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,qBAiO5C"}
@@ -20,7 +20,7 @@ const RMEEscalationList = React.lazy(() => import(/* webpackChunkName: 'RMEEscal
20
20
  export function CaseDetailsTabs(props) {
21
21
  const { caseNumber } = props;
22
22
  const { activeTab } = useParams();
23
- const { globalMetadataState: { loggedInUserRights }, } = useContext(GlobalMetadataStateContext);
23
+ const { globalMetadataState: { loggedInUserRights, loggedInUsersAccount }, } = useContext(GlobalMetadataStateContext);
24
24
  const { accountNumber, chats, comments, status } = useCaseSelector((state) => ({
25
25
  accountNumber: state.caseDetails.accountNumberRef,
26
26
  chats: state.caseDetails.chats,
@@ -104,14 +104,15 @@ export function CaseDetailsTabs(props) {
104
104
  routePath: 'escalation',
105
105
  component: (React.createElement(RMEEscalationList, { escalations: caseEscalations.data, caseNumber: caseNumber, caseStatus: status, accountNumber: loggedInUserRights.data.getAccountNumber(), isInternal: loggedInUserRights.data.isInternal() })),
106
106
  });
107
- tabsToRender.push({
108
- 'data-tracking-id': 'case-history-tab',
109
- title: CaseDetailsTabsEnum.HISTORY,
110
- key: 'history',
111
- routePath: 'history',
112
- ref: caseHistoryTabRef,
113
- component: React.createElement(CaseHistory, { caseNumber: caseNumber }),
114
- });
107
+ !loggedInUsersAccount.data.secureSupport &&
108
+ tabsToRender.push({
109
+ 'data-tracking-id': 'case-history-tab',
110
+ title: CaseDetailsTabsEnum.HISTORY,
111
+ key: 'history',
112
+ routePath: 'history',
113
+ ref: caseHistoryTabRef,
114
+ component: React.createElement(CaseHistory, { caseNumber: caseNumber }),
115
+ });
115
116
  const getActiveTabKey = () => {
116
117
  if (!activeTab)
117
118
  return activeTabKey;
@@ -1 +1 @@
1
- {"version":3,"file":"CaseType.d.ts","sourceRoot":"","sources":["../../../../../src/components/CaseEditView/CaseOverview/CaseType.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAW,MAAM,0BAA0B,CAAC;AAGrE,OAAO,KAA+B,MAAM,OAAO,CAAC;AAOpD,UAAU,MAAO,SAAQ,gBAAgB;IACrC,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACpD,UAAU,EAAE,OAAO,CAAC;IACpB,QAAQ,EAAE,GAAG,CAAC;IACd,UAAU,EAAE,OAAO,CAAC;IACpB,QAAQ,EAAE,OAAO,CAAC;CACrB;AAOD,iBAAS,QAAQ,CAAC,KAAK,EAAE,MAAM,qBAsD9B;kBAtDQ,QAAQ;;;AAyDjB,eAAe,QAAQ,CAAC"}
1
+ {"version":3,"file":"CaseType.d.ts","sourceRoot":"","sources":["../../../../../src/components/CaseEditView/CaseOverview/CaseType.tsx"],"names":[],"mappings":"AAWA,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAG5D,OAAO,KAAoC,MAAM,OAAO,CAAC;AAOzD,UAAU,MAAO,SAAQ,gBAAgB;IACrC,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACpD,UAAU,EAAE,OAAO,CAAC;IACpB,QAAQ,EAAE,GAAG,CAAC;IACd,UAAU,EAAE,OAAO,CAAC;IACpB,QAAQ,EAAE,OAAO,CAAC;CACrB;AAOD,iBAAS,QAAQ,CAAC,KAAK,EAAE,MAAM,qBAoF9B;kBApFQ,QAAQ;;;AAuFjB,eAAe,QAAQ,CAAC"}
@@ -7,8 +7,9 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
7
7
  step((generator = generator.apply(thisArg, _arguments || [])).next());
8
8
  });
9
9
  };
10
- import { Dropdown, ValueChangedIcon } from '@rh-support/components';
11
- import { toOldCaseTypeSwitcher, toOption, toOptions } from '@rh-support/utils';
10
+ import { Flex, FlexItem, MenuToggle, Select, SelectList, SelectOption, Spinner, } from '@patternfly/react-core';
11
+ import { ValueChangedIcon } from '@rh-support/components';
12
+ import { toOldCaseTypeSwitcher } from '@rh-support/utils';
12
13
  import isEmpty from 'lodash/isEmpty';
13
14
  import React, { useContext, useState } from 'react';
14
15
  import { Trans, useTranslation } from 'react-i18next';
@@ -23,16 +24,28 @@ function CaseType(props) {
23
24
  const { t } = useTranslation();
24
25
  const [isCaseTypeInValid, setIsCaseTypeInValid] = useState(false);
25
26
  const { isExportingPDF } = useContext(PDFContext);
27
+ const [isOpen, setIsOpen] = useState(false);
28
+ const [selected, setSelected] = useState(props.selectedType);
29
+ const onToggleClick = () => {
30
+ setIsOpen(!isOpen);
31
+ };
32
+ const toggle = (toggleRef) => (React.createElement(MenuToggle, { ref: toggleRef, onClick: onToggleClick, isExpanded: isOpen, isDisabled: props.hasError || props.isDisabled || props.isFetching, isFullWidth: true, status: isCaseTypeInValid ? 'danger' : undefined, className: "case-type-selector-text" },
33
+ React.createElement(Flex, { justifyContent: { default: 'justifyContentSpaceBetween' } },
34
+ React.createElement(FlexItem, null,
35
+ " ",
36
+ selected || t(`Select a category`)),
37
+ React.createElement(FlexItem, null, props.isFetching ? React.createElement(Spinner, { size: "md" }) : ''))));
26
38
  const validateCaseType = (selectedItem) => {
27
39
  setIsCaseTypeInValid(isEmpty(selectedItem));
28
40
  };
29
41
  const onCaseTypeChange = (option) => __awaiter(this, void 0, void 0, function* () {
30
- const switchedCaseType = toOldCaseTypeSwitcher(option.value);
42
+ const switchedCaseType = toOldCaseTypeSwitcher(option);
31
43
  if (switchedCaseType === props.selectedType) {
32
44
  return;
33
45
  }
34
46
  yield props.onTypeChange(switchedCaseType);
35
47
  setLocalTypeChange(true);
48
+ setSelected(option);
36
49
  validateCaseType(option);
37
50
  });
38
51
  // value changed logic to show a non local type change
@@ -43,7 +56,8 @@ function CaseType(props) {
43
56
  React.createElement(Trans, null, "Support type"),
44
57
  React.createElement(ValueChangedIcon, { afterLocalChange: afterLocalChange, isLocalChange: localTypeChange, value: props.selectedType, getTooltipContent: getChangedValueTooltip(() => CaseValuesToWatch.type) }),
45
58
  React.createElement("span", { className: `form-required ${isExportingPDF ? 'hide-in-pdf' : ''}`, "aria-hidden": true }, "*")),
46
- React.createElement(Dropdown, { name: "get-support-type", placeholder: t(`Select`), title: t(`Select a category`), list: toOptions(props.allTypes || []), selectedItem: toOption(props.selectedType), disabled: props.hasError || props.isDisabled, isLoadingList: props.isFetching, isInValid: isCaseTypeInValid, required: true, onChange: onCaseTypeChange, onOuterClick: validateCaseType, "data-tracking-id": "case-details-type-selector" })));
59
+ React.createElement(Select, { "data-tracking-id": "case-details-type-selector", isOpen: isOpen, selected: selected, onSelect: (event, val) => onCaseTypeChange(val), onOpenChange: (isOpen) => setIsOpen(isOpen), toggle: toggle, popperProps: { direction: 'down', enableFlip: false }, shouldFocusFirstItemOnOpen: false, shouldFocusToggleOnSelect: true },
60
+ React.createElement(SelectList, null, (props.allTypes || []).map((option) => (React.createElement(SelectOption, { value: option, key: option }, option)))))));
47
61
  }
48
62
  CaseType.defaultProps = defaultProps;
49
63
  export default CaseType;
@@ -1 +1 @@
1
- {"version":3,"file":"CommentSearch.d.ts","sourceRoot":"","sources":["../../../../../../src/components/CaseEditView/Tabs/CaseDiscussion/CommentSearch.tsx"],"names":[],"mappings":"AAOA,OAAO,KAAmB,MAAM,OAAO,CAAC;AAGxC,OAAO,EAAkB,WAAW,EAAE,MAAM,+CAA+C,CAAC;AAE5F,UAAU,MAAM;IACZ,eAAe,EAAE,WAAW,EAAE,CAAC;IAC/B,eAAe,CAAC,EAAE,CAAC,YAAY,EAAE,MAAM,EAAE,EAAE,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC;IACxE,sBAAsB,EAAE,OAAO,CAAC;CACnC;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,qBAoG1C"}
1
+ {"version":3,"file":"CommentSearch.d.ts","sourceRoot":"","sources":["../../../../../../src/components/CaseEditView/Tabs/CaseDiscussion/CommentSearch.tsx"],"names":[],"mappings":"AAOA,OAAO,KAAmB,MAAM,OAAO,CAAC;AAGxC,OAAO,EAAkB,WAAW,EAAE,MAAM,+CAA+C,CAAC;AAE5F,UAAU,MAAM;IACZ,eAAe,EAAE,WAAW,EAAE,CAAC;IAC/B,eAAe,CAAC,EAAE,CAAC,YAAY,EAAE,MAAM,EAAE,EAAE,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC;IACxE,sBAAsB,EAAE,OAAO,CAAC;CACnC;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,qBAqG1C"}
@@ -10,7 +10,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
10
10
  import { Button, TextInput } from '@patternfly/react-core';
11
11
  import TimesIcon from '@patternfly/react-icons/dist/js/icons/times-icon';
12
12
  import { humanizeSize } from '@rh-support/utils';
13
- import SearchApi, { INDEX_MODES } from 'js-worker-search';
13
+ import SearchApi from 'js-worker-search';
14
14
  import isEmpty from 'lodash/isEmpty';
15
15
  import React, { useState } from 'react';
16
16
  import { Trans, useTranslation } from 'react-i18next';
@@ -32,8 +32,9 @@ export function CommentSearch(props) {
32
32
  props.onCommentSearch([], '');
33
33
  return;
34
34
  }
35
+ // Removing indexMode: INDEX_MODES.PREFIXES parameter from SearchAPI to match all sub-strings by default
36
+ // Refer https://github.com/bvaughn/js-worker-search?tab=readme-ov-file#custom-index-mode
35
37
  const searchApi = new SearchApi({
36
- indexMode: INDEX_MODES.PREFIXES,
37
38
  caseSensitive: false,
38
39
  matchAnyToken: true,
39
40
  });
@@ -5,10 +5,14 @@
5
5
  .timeline {
6
6
  position: relative;
7
7
  max-width: 100%;
8
- margin: 0 auto;
8
+ margin: 24px auto;
9
9
  padding: 0 20px;
10
10
  }
11
11
 
12
+ .timeline-empty::after {
13
+ display: none;
14
+ }
15
+
12
16
  .timeline::after {
13
17
  content: '';
14
18
  position: absolute;
@@ -21,7 +25,7 @@
21
25
 
22
26
  /* This value is calculated in timeline.tsx */
23
27
  bottom: calc(var(--timeline-bottom) + var(--timeline-bottom-offset, 18.35%));
24
- left: calc(13% + 13px);
28
+ left: calc(15% + 15px);
25
29
  transform: translateX(-50%);
26
30
  }
27
31
 
@@ -45,18 +49,49 @@
45
49
  z-index: 1;
46
50
  }
47
51
 
52
+ .timeline-controls {
53
+ display: flex;
54
+ justify-content: space-between;
55
+ align-items: center;
56
+ padding: 0.5rem 1rem;
57
+ margin: 0 -0.8rem;
58
+ }
59
+
60
+ .timeline-pagination {
61
+ flex-grow: 1;
62
+ display: flex;
63
+ align-items: center;
64
+ }
65
+ #options-menu-top-pagination {
66
+ display: flex !important;
67
+ flex-wrap: nowrap !important;
68
+ }
69
+ .timeline-sort-order-select {
70
+ width: auto;
71
+ margin-left: 1rem;
72
+ }
73
+
74
+ .timeline-controls:last-of-type {
75
+ justify-content: flex-start;
76
+ }
77
+
78
+ .timeline-controls:last-of-type .timeline-pagination {
79
+ flex-grow: 0;
80
+ }
81
+
48
82
  .timeline-node {
49
83
  display: flex;
50
84
  justify-content: space-between;
51
85
  align-items: flex-start;
52
86
  position: relative;
53
- margin-bottom: 20px;
87
+ margin-bottom: 32px;
54
88
  min-height: 80px;
89
+ max-height: 1em;
55
90
  }
56
91
 
57
92
  .timeline-avatar {
58
93
  position: absolute;
59
- left: calc(13% + 13px);
94
+ left: calc(15% + 15px);
60
95
  transform: translateX(-91%);
61
96
  top: 12px;
62
97
  z-index: 5;
@@ -69,15 +104,17 @@
69
104
  width: 10px;
70
105
  height: 10px;
71
106
  z-index: 2;
72
- left: calc(13% + 13px);
107
+ left: calc(15% + 15px);
73
108
  transform: translateX(-195%);
74
109
  top: 25px;
75
110
  }
76
111
 
77
112
  .left-node {
78
- flex: 0 0 13%;
79
- max-width: 13%;
113
+ flex: 0 0 15%;
114
+ max-width: 20%;
80
115
  padding-right: 24px;
116
+ margin-left: -2em;
117
+ margin-right: 24px;
81
118
  }
82
119
 
83
120
  .content-date-left-history {
@@ -96,6 +133,9 @@
96
133
  font-weight: 400;
97
134
  text-align: right;
98
135
  line-height: 30px;
136
+ padding-left: 1em;
137
+ white-space: nowrap;
138
+ overflow: hidden;
99
139
  }
100
140
 
101
141
  .content-date-right-history {
@@ -121,29 +161,27 @@
121
161
  .right-node {
122
162
  flex-grow: 1;
123
163
  padding-left: 2.8%;
164
+ margin-left: 1%;
124
165
  }
125
166
 
126
167
  .right-node::before {
127
168
  content: ' ';
128
- height: 0;
129
- position: relative;
130
- display: list-item;
169
+ position: absolute;
131
170
  top: 22.5px;
132
171
  width: 0;
133
- z-index: 1;
134
- left: -0.5%;
172
+ height: 0;
135
173
  border: medium solid white;
136
- border-width: 7px 0 7px 7px;
137
- border-color: transparent transparent transparent white;
138
- transform: rotate(180deg);
174
+ border-width: 7px 7px 7px 0;
175
+ border-color: transparent white transparent transparent;
176
+ transform: translateX(-100%);
139
177
  }
140
178
 
141
179
  .internal.right-node::before {
142
- border-color: transparent transparent transparent #ee0000;
180
+ border-right-color: #ee0000;
143
181
  }
144
182
 
145
183
  .customer.right-node::before {
146
- border-color: transparent transparent transparent #316dc1;
184
+ border-right-color: #316dc1;
147
185
  }
148
186
 
149
187
  .timeline-internal {
@@ -168,9 +206,9 @@
168
206
 
169
207
  .contentTimeline {
170
208
  padding: 16px;
171
- position: absolute;
209
+ /* position: absolute; */
172
210
  border-radius: 3px;
173
- margin-bottom: 32px;
211
+ /* margin-bottom: 32px; */
174
212
  }
175
213
 
176
214
  .content-right-history {
@@ -179,8 +217,7 @@
179
217
  border-left-style: solid !important;
180
218
  border-radius: 3px;
181
219
  border: 1px solid #d2d2d2;
182
- width: 80%;
183
- top: 0rem;
220
+ width: 100%;
184
221
  }
185
222
 
186
223
  .content-right-customer {
@@ -203,6 +240,9 @@ ul#case-history-paginated-timeline {
203
240
 
204
241
  .timelineMenu {
205
242
  display: flex;
243
+ justify-content: space-between;
244
+ align-items: center;
245
+ margin-bottom: 1rem;
206
246
  }
207
247
 
208
248
  .case-history-timeline-datepicker {
@@ -224,6 +264,16 @@ ul#case-history-paginated-timeline {
224
264
  width: 93.2%;
225
265
  }
226
266
 
267
+ @-moz-document url-prefix() {
268
+ .timeline-controls {
269
+ padding: 0.5rem 1rem;
270
+ }
271
+
272
+ #options-menu-top-pagination {
273
+ width: 15em;
274
+ }
275
+ }
276
+
227
277
  @media screen and (max-width: 768px) {
228
278
  .timeline::after {
229
279
  left: 20px;
@@ -1 +1 @@
1
- {"version":3,"file":"Timeline.d.ts","sourceRoot":"","sources":["../../../../../../src/components/CaseEditView/Tabs/CaseHistory/Timeline.tsx"],"names":[],"mappings":"AAAA,OAAO,gBAAgB,CAAC;AAwBxB,OAAO,KAAuD,MAAM,OAAO,CAAC;AAoO5E,QAAA,MAAM,QAAQ;;uBAgRb,CAAC;AACF,eAAe,QAAQ,CAAC"}
1
+ {"version":3,"file":"Timeline.d.ts","sourceRoot":"","sources":["../../../../../../src/components/CaseEditView/Tabs/CaseHistory/Timeline.tsx"],"names":[],"mappings":"AAAA,OAAO,gBAAgB,CAAC;AA0BxB,OAAO,KAAuD,MAAM,OAAO,CAAC;AA4P5E,QAAA,MAAM,QAAQ;;uBAwRb,CAAC;AACF,eAAe,QAAQ,CAAC"}
@@ -9,9 +9,11 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
9
9
  };
10
10
  import './Timeline.css';
11
11
  import { caseHistory } from '@cee-eng/hydrajs';
12
- import { Avatar, Button, DatePicker, EmptyState, EmptyStateBody, EmptyStateHeader, EmptyStateIcon, EmptyStateVariant, MenuToggle, SearchInput, Select, SelectList, SelectOption, Spinner, } from '@patternfly/react-core';
12
+ import { Avatar, Button, DatePicker, EmptyState, EmptyStateBody, EmptyStateHeader, EmptyStateIcon, EmptyStateVariant, MenuToggle, Pagination, SearchInput, Select, SelectOption, Spinner, } from '@patternfly/react-core';
13
+ import ExclamationCircleIcon from '@patternfly/react-icons/dist/js/icons/exclamation-circle-icon';
13
14
  import SearchIcon from '@patternfly/react-icons/dist/js/icons/search-icon';
14
- import { PaginatedList } from '@rh-support/components';
15
+ import globalDangerColor100 from '@patternfly/react-tokens/dist/js/global_danger_color_100';
16
+ import { format, fromUnixTime, isSameDay, parse } from 'date-fns';
15
17
  import debounce from 'lodash/debounce';
16
18
  import isEmpty from 'lodash/isEmpty';
17
19
  import React, { useEffect, useLayoutEffect, useRef, useState } from 'react';
@@ -37,7 +39,7 @@ const TimelineEvent = ({ date, text, side, user, useAvatar }) => {
37
39
  const TimelineNode = React.forwardRef(({ leftEvent, rightEvent, user, useAvatar }, ref) => {
38
40
  return (React.createElement("div", { className: "timeline-node", role: "region", "aria-label": "Timeline node" },
39
41
  leftEvent && React.createElement(TimelineEvent, Object.assign({}, leftEvent, { side: "left", useAvatar: useAvatar })),
40
- React.createElement("div", { ref: ref, "aria-label": `${useAvatar ? 'Open user profile' : 'Marker'}`, tabIndex: 0 }, useAvatar ? (React.createElement(Avatar, { src: 'https://www.patternfly.org/images/668560cd.svg', className: `timeline-avatar timeline-avatar-${user}`, alt: `${user}'s avatar` })) : (React.createElement("div", { className: `timeline-marker timeline-${user}` }))),
42
+ React.createElement("div", { ref: ref, "aria-label": `${useAvatar ? 'User profile picture' : 'Timeline marker'}`, tabIndex: 0 }, useAvatar ? (React.createElement(Avatar, { src: 'https://www.patternfly.org/images/668560cd.svg', className: `timeline-avatar timeline-avatar-${user}`, alt: `${user}'s avatar` })) : (React.createElement("div", { className: `timeline-marker timeline-${user}` }))),
41
43
  rightEvent && React.createElement(TimelineEvent, Object.assign({}, rightEvent, { side: "right" }))));
42
44
  });
43
45
  //Handling changes in case fields to be displayed to the user
@@ -55,6 +57,20 @@ const applyReplacements = (item) => {
55
57
  BusinessHoursId: 'Business Hours',
56
58
  FolderId__c: 'Case Group',
57
59
  Status: 'Status',
60
+ Customer_Escalation__c: 'Customer Escalation',
61
+ SlaStartDate: 'SLA Start Date',
62
+ Case_Language__c: 'Case Language',
63
+ };
64
+ const languageCodeMapping = {
65
+ de: 'German',
66
+ en: 'English',
67
+ es: 'Spanish',
68
+ fr: 'French',
69
+ it: 'Italian',
70
+ pt: 'Portuguese',
71
+ ko: 'Korean',
72
+ jp: 'Japanese',
73
+ zh: 'Chinese',
58
74
  };
59
75
  let fieldName = fieldNameMapping[item.fieldName] || item.fieldLabel || item.fieldName || '';
60
76
  const getNameValue = (prefix) => {
@@ -66,15 +82,30 @@ const applyReplacements = (item) => {
66
82
  Entitlement: 'entitlement',
67
83
  'Business Hours': 'businessHours',
68
84
  Owner: 'queueNameOwner',
85
+ 'Customer Escalation': 'customerEscalation',
86
+ 'Case Group': 'caseGroup',
87
+ 'SLA Start Date': 'slaStartDate',
88
+ 'Case Language': 'caseLanguage',
69
89
  };
70
90
  const baseKey = keyMap[fieldName] || fieldName.replace(/\s/g, '');
71
91
  const key = `${baseKey}${prefix}Name`;
72
92
  return item[key] || item[`${prefix}Value`] || '';
73
93
  };
74
- const newValue = getNameValue('New');
75
- const oldValue = getNameValue('Old');
94
+ let newValue = getNameValue('New');
95
+ let oldValue = getNameValue('Old');
76
96
  let newText = '';
77
- if (item.fieldName === 'OwnerId' && item.createdByUserName) {
97
+ if (item.fieldName === 'Case_Language__c') {
98
+ // Map language codes to language names
99
+ const newLanguage = languageCodeMapping[item.newValue] || item.newValue;
100
+ const oldLanguage = languageCodeMapping[item.oldValue] || item.oldValue;
101
+ if (item.oldValue && item.newValue) {
102
+ newText = `changed ${fieldName} from ${oldLanguage} to ${newLanguage}`;
103
+ }
104
+ else if (item.newValue) {
105
+ newText = `set ${fieldName} to ${newLanguage}`;
106
+ }
107
+ }
108
+ else if (item.fieldName === 'OwnerId' && item.createdByUserName) {
78
109
  newText = `set ${fieldName} to ${item.createdByUserName}`;
79
110
  }
80
111
  else if (item.fieldName === 'Status') {
@@ -112,40 +143,43 @@ const applyReplacements = (item) => {
112
143
  return newText;
113
144
  };
114
145
  // function to change the apiResponse
115
- const specialTimelineData = (apiResponse) => {
116
- return Object.assign(Object.assign({}, apiResponse), { historyItems: apiResponse.historyItems.map((item) => (Object.assign(Object.assign({}, item), { outputText: item.type === 'Change' ? applyReplacements(item) : item.outputText }))) });
117
- };
118
146
  const transformApiResponseToTimelineData = (apiResponse) => {
119
147
  let previousUser = null;
120
- const modifiedApiResponse = specialTimelineData(apiResponse);
121
- const timelineEvents = modifiedApiResponse.historyItems.map((item, index) => {
148
+ const timelineEvents = apiResponse.historyItems
149
+ // Filter out 'Case Group' changes because we don't have decode of value
150
+ .filter((item) => item.fieldName !== 'FolderId__c')
151
+ .map((item, index) => {
122
152
  const currentUser = item.createdByUserName;
123
- // If the current user is the same as the previous one, and it's not the first item, don't use an avatar. use !! cause previousUser start null.
124
153
  const useAvatar = index === 0 || (!!previousUser && currentUser !== previousUser);
125
- // Update the previousUser for the next iteration
126
154
  previousUser = currentUser;
127
- const eventDate = new Date(item.createdDate);
128
- const date = eventDate.toLocaleDateString('en-US', { year: 'numeric', month: 'long', day: 'numeric' });
129
- const time = eventDate.toLocaleTimeString('en-US', {
130
- hour: 'numeric',
131
- minute: '2-digit',
132
- hour12: true,
133
- timeZoneName: 'short',
134
- });
155
+ let eventDate;
156
+ if (typeof item.createdDate === 'string' && item.createdDate.includes('T')) {
157
+ eventDate = parse(item.createdDate, "yyyy-MM-dd'T'HH:mm:ss'Z'", new Date());
158
+ }
159
+ else {
160
+ eventDate = fromUnixTime(item.createdDate / 1000);
161
+ }
135
162
  const user = item.createdByCustomer !== undefined
136
- ? item.createdByCustomer //using new case history field to determine this
163
+ ? item.createdByCustomer
137
164
  ? 'customer'
138
165
  : 'internal'
139
- : currentUser === 'Case Diagnostics' || currentUser === 'GSS Tools' //for now since it is not on prod yet we have this same fallback
166
+ : currentUser === 'Case Diagnostics' || currentUser === 'GSS Tools'
140
167
  ? 'internal'
141
168
  : 'customer';
142
169
  const leftEvent = {
143
- date: date,
144
- text: time,
170
+ date: format(eventDate, 'MMMM d, yyyy'),
171
+ text: format(eventDate, 'h:mm a zzz'),
145
172
  };
173
+ let outputText = item.outputText;
174
+ if (item.type === 'Change') {
175
+ outputText = applyReplacements(item);
176
+ }
177
+ else {
178
+ outputText = stripHTML(outputText);
179
+ }
146
180
  const rightEvent = {
147
- date: `${item.createdByUserName} ${stripHTML(item.outputText)}`, //will change name later from date, for now date is title and text stays text due to initial set up mimicking same ITimelineEvent
148
- text: '', //future iterations of API make this the 'show more' field
181
+ date: `${item.createdByUserName} ${outputText}`,
182
+ text: '',
149
183
  user: user,
150
184
  useAvatar: useAvatar,
151
185
  };
@@ -165,13 +199,28 @@ const Timeline = ({ caseNumber }) => {
165
199
  const { t } = useTranslation();
166
200
  const [timelineEvents, setTimelineEvents] = useState([]);
167
201
  const [isFetchingData, setIsFetchingData] = useState();
168
- const [paginatedListLength, setPaginatedListLength] = useState();
169
202
  const lastNodeRef = useRef(null);
170
203
  const [dateValue, setDateValue] = React.useState('');
171
204
  const [searchValue, setSearchValue] = useState('');
172
205
  const [filteredEvents, setFilteredEvents] = useState([]);
173
206
  const [isSelectOpen, setIsSelectOpen] = useState(false);
174
207
  const [selectedOrder, setSelectedOrder] = useState('Newest to Oldest');
208
+ const [fetchError, setFetchError] = useState(null);
209
+ const [page, setPage] = useState(1);
210
+ const [perPage, setPerPage] = useState(20);
211
+ const onSetPage = (_, newPage) => {
212
+ setPage(newPage);
213
+ };
214
+ const onPerPageSelect = (_, newPerPage) => {
215
+ setPerPage(newPerPage);
216
+ setPage(1);
217
+ };
218
+ const renderPagination = () => (React.createElement(Pagination, { itemCount: filteredEvents.length, perPage: perPage, page: page, onSetPage: onSetPage, onPerPageSelect: onPerPageSelect, perPageOptions: [
219
+ { title: '5', value: 5 },
220
+ { title: '10', value: 10 },
221
+ { title: '15', value: 15 },
222
+ { title: '20', value: 20 },
223
+ ], isCompact: true, variant: "top" }));
175
224
  const handleSelectToggle = () => {
176
225
  setIsSelectOpen(!isSelectOpen);
177
226
  };
@@ -199,6 +248,7 @@ const Timeline = ({ caseNumber }) => {
199
248
  function fetchHistory() {
200
249
  return __awaiter(this, void 0, void 0, function* () {
201
250
  setIsFetchingData(true);
251
+ setFetchError(null);
202
252
  const options = {
203
253
  sortField: 'createdDate',
204
254
  sortOrder: 'DESC',
@@ -211,6 +261,7 @@ const Timeline = ({ caseNumber }) => {
211
261
  }
212
262
  catch (error) {
213
263
  console.error('Failed to fetch history:', error);
264
+ setFetchError('Unable to connect');
214
265
  }
215
266
  finally {
216
267
  setIsFetchingData(false);
@@ -218,7 +269,6 @@ const Timeline = ({ caseNumber }) => {
218
269
  });
219
270
  }
220
271
  fetchHistory();
221
- // eslint-disable-next-line react-hooks/exhaustive-deps
222
272
  }, [caseNumber]);
223
273
  //Using useLayoutEffect because we are measuring styles based on DOM, useLayoutEffect runs after DOM Mutations https://react.dev/reference/react/useLayoutEffect
224
274
  useLayoutEffect(() => {
@@ -229,16 +279,16 @@ const Timeline = ({ caseNumber }) => {
229
279
  const timelineElement = document.querySelector('.timeline');
230
280
  const avatarHeight = ((_a = lastNodeRef.current.querySelector('.timeline-avatar')) === null || _a === void 0 ? void 0 : _a.clientHeight) || 0;
231
281
  if (timelineElement) {
232
- // Get the timeline element's position relative to the document
233
282
  const timelineTop = timelineElement.getBoundingClientRect().top + window.scrollY;
234
- // Calculate value relative to the timeline's top must be adjusted for page scroll or we get random bottom value based on where user scrolled before execution
235
283
  const calculatedBottomValue = `${timelineTop + timelineElement.offsetHeight - timelineBottom + avatarHeight}px`;
236
284
  timelineElement.style.setProperty('--timeline-bottom', calculatedBottomValue);
237
285
  }
238
286
  }
239
287
  }, 100);
240
288
  updateLineStyle();
241
- }, [timelineEvents, paginatedListLength, dateValue]);
289
+ window.addEventListener('resize', updateLineStyle);
290
+ return () => window.removeEventListener('resize', updateLineStyle);
291
+ }, [timelineEvents, perPage, dateValue]);
242
292
  const handleSearchChange = (value) => {
243
293
  setSearchValue(value.target.value);
244
294
  };
@@ -254,60 +304,62 @@ const Timeline = ({ caseNumber }) => {
254
304
  const lowercasedFilter = searchValue.toLowerCase();
255
305
  filteredBySearch = filteredBySearch.filter(({ left, right }) => {
256
306
  const dateString = left.date.toLowerCase();
307
+ const timeString = left.text.toLowerCase();
257
308
  return (dateString.includes(lowercasedFilter) ||
258
- left.text.toLocaleLowerCase().includes(lowercasedFilter) ||
309
+ timeString.includes(lowercasedFilter) ||
259
310
  right.date.toLowerCase().includes(lowercasedFilter));
260
311
  });
261
312
  }
262
313
  let finalFilteredEvents = filteredBySearch;
263
314
  if (dateValue) {
264
315
  finalFilteredEvents = filteredBySearch.filter(({ left }) => {
265
- // Format the event date to match the DatePicker format (YYYY-MM-DD) We need to do it this way so we dont have discrepancy (off by one month when selecting) due to the way that JS handles timezones
266
- const eventDateFormatted = new Date(left.date).toISOString().split('T')[0];
267
- // Compare the formatted event date with the selected date from DatePicker
268
- return eventDateFormatted === dateValue;
316
+ const eventDate = parse(left.date, 'MMMM d, yyyy', new Date());
317
+ const selectedDate = parse(dateValue, 'yyyy-MM-dd', new Date());
318
+ return isSameDay(eventDate, selectedDate);
269
319
  });
270
320
  }
271
321
  setFilteredEvents(finalFilteredEvents);
272
322
  }, [searchValue, dateValue, timelineEvents]);
273
- if (filteredEvents.length < 1 && !isFetchingData) {
274
- return (React.createElement("div", { key: "no-results" },
275
- React.createElement("div", { className: "timelineMenu" },
276
- React.createElement(SearchInput, { placeholder: t('Search for a user, action, or keyword'), value: searchValue, onChange: handleSearchChange, onClear: handleClear, className: "case-history-timeline-search" }),
277
- React.createElement("div", { className: "case-history-timeline-datepicker" },
278
- React.createElement(DatePicker, { value: dateValue, onChange: (_event, value) => handleDateChange(value) }),
279
- React.createElement(Button, { onClick: () => setDateValue(''), isDisabled: isEmpty(dateValue) }, "Reset"))),
280
- React.createElement("div", { className: "timeline-sort-order-select" },
281
- React.createElement(Select, { id: "order-select", isOpen: isSelectOpen, selected: selectedOrder, onSelect: handleSelect, onOpenChange: (isOpen) => setIsSelectOpen(isOpen), toggle: (toggleRef) => (React.createElement(MenuToggle, { ref: toggleRef, onClick: handleSelectToggle, isExpanded: isSelectOpen, style: { width: '200px' } }, selectedOrder)), shouldFocusToggleOnSelect: true },
282
- React.createElement(SelectList, null,
283
- React.createElement(SelectOption, { value: "Newest to Oldest" }, "Newest to Oldest"),
284
- React.createElement(SelectOption, { value: "Oldest to Newest" }, "Oldest to Newest")))),
285
- React.createElement(EmptyState, { variant: EmptyStateVariant.full },
323
+ const handleReload = (e) => {
324
+ e.preventDefault();
325
+ window.location.href = window.location.href;
326
+ window.location.reload();
327
+ };
328
+ const renderTimelineContent = () => {
329
+ if (fetchError) {
330
+ return (React.createElement(EmptyState, { variant: EmptyStateVariant.full },
331
+ React.createElement(EmptyStateHeader, { titleText: "Unable to connect", icon: React.createElement(EmptyStateIcon, { icon: ExclamationCircleIcon, color: globalDangerColor100.value }), headingLevel: "h2" }),
332
+ React.createElement(EmptyStateBody, null,
333
+ React.createElement(Trans, null,
334
+ "Try ",
335
+ ' ',
336
+ React.createElement("a", { href: "#", onClick: handleReload }, "reloading the page"),
337
+ ' ',
338
+ "or check back later"))));
339
+ }
340
+ if (filteredEvents.length < 1) {
341
+ return (React.createElement(EmptyState, { variant: EmptyStateVariant.full },
286
342
  React.createElement(EmptyStateHeader, { titleText: React.createElement(Trans, null, "No results found"), icon: React.createElement(EmptyStateIcon, { icon: SearchIcon }), headingLevel: "h2" }),
287
343
  React.createElement(EmptyStateBody, null,
288
- React.createElement(Trans, null, "Try modifying your search query or changing the date range and try again.")))));
289
- }
344
+ React.createElement(Trans, null, "Try modifying your search query or changing the date range and try again."))));
345
+ }
346
+ return (React.createElement(React.Fragment, null, filteredEvents.slice((page - 1) * perPage, page * perPage).map((node, index) => (React.createElement(TimelineNode, { key: index, leftEvent: node.left, rightEvent: node.right, user: node.right.user, useAvatar: node.right.useAvatar, ref: index === perPage - 1 ? lastNodeRef : null })))));
347
+ };
290
348
  return (React.createElement(React.Fragment, null,
291
349
  React.createElement("div", { className: "timelineMenu" },
292
- React.createElement(SearchInput, { placeholder: "Search for a user, action, or keyword", value: searchValue, onChange: handleSearchChange, onClear: handleClear, className: "case-history-timeline-search" }),
350
+ React.createElement(SearchInput, { placeholder: t('Search for a user, action, or keyword'), value: searchValue, onChange: handleSearchChange, onClear: handleClear, className: "case-history-timeline-search" }),
293
351
  React.createElement("div", { className: "case-history-timeline-datepicker" },
294
352
  React.createElement(DatePicker, { value: dateValue, onChange: (_event, value) => handleDateChange(value) }),
295
353
  React.createElement(Button, { onClick: () => setDateValue(''), isDisabled: isEmpty(dateValue) }, "Reset"))),
296
- React.createElement("div", { className: "timeline-sort-order-select" },
297
- React.createElement(Select, { id: "order-select", isOpen: isSelectOpen, selected: selectedOrder, onSelect: handleSelect, onOpenChange: (isOpen) => setIsSelectOpen(isOpen), toggle: (toggleRef) => (React.createElement(MenuToggle, { ref: toggleRef, onClick: handleSelectToggle, isExpanded: isSelectOpen, style: { width: '200px' } }, selectedOrder)), shouldFocusToggleOnSelect: true },
298
- React.createElement(SelectList, null,
354
+ React.createElement("div", { className: "timeline-controls" },
355
+ React.createElement("div", { className: "timeline-pagination" }, renderPagination()),
356
+ React.createElement("div", { className: "timeline-sort-order-select" },
357
+ React.createElement(Select, { id: "order-select", isOpen: isSelectOpen, selected: selectedOrder, onSelect: handleSelect, onOpenChange: (isOpen) => setIsSelectOpen(isOpen), toggle: (toggleRef) => (React.createElement(MenuToggle, { ref: toggleRef, onClick: handleSelectToggle, isExpanded: isSelectOpen, style: { width: '200px' } }, selectedOrder)), shouldFocusToggleOnSelect: true },
299
358
  React.createElement(SelectOption, { value: "Newest to Oldest" }, "Newest to Oldest"),
300
359
  React.createElement(SelectOption, { value: "Oldest to Newest" }, "Oldest to Newest")))),
301
- React.createElement("div", { className: "timeline" },
302
- isFetchingData && (React.createElement("div", { className: "timeline-loading-spinner" },
303
- React.createElement(Spinner, { size: "xl" }))),
304
- !isFetchingData && (React.createElement(PaginatedList, { id: "case-history-paginated-timeline", listItems: filteredEvents &&
305
- filteredEvents.map((node, index) => (React.createElement(TimelineNode, { key: index, leftEvent: node.left, rightEvent: node.right, user: node.right.user, useAvatar: node.right.useAvatar, ref: index === (paginatedListLength && paginatedListLength - 1) ? lastNodeRef : null //this ref is needed to perform calculations on the final node height
306
- }))), perPage: 20, perPageOptions: [
307
- { title: '5', value: 5 },
308
- { title: '10', value: 10 },
309
- { title: '15', value: 15 },
310
- { title: '20', value: 20 },
311
- ], setPaginatedListLength: setPaginatedListLength })))));
360
+ isFetchingData ? (React.createElement("div", { className: "timeline-loading-spinner" },
361
+ React.createElement(Spinner, { size: "xl" }))) : (React.createElement("div", { className: `timeline ${filteredEvents.length === 0 ? 'timeline-empty' : ''}` }, renderTimelineContent())),
362
+ React.createElement("div", { className: "timeline-controls" },
363
+ React.createElement("div", { className: "timeline-pagination" }, renderPagination()))));
312
364
  };
313
365
  export default Timeline;
@@ -168,11 +168,11 @@ export default function SubmitCase(props) {
168
168
  React.createElement("div", { className: "submit-case-header-container" },
169
169
  React.createElement("p", { className: "kicker kicker-sm pf-v5-u-mb-sm" }, !isEmpty(RouteUtils.seBasePath) &&
170
170
  !isUploadingAttachment(attachmentState.caseFiles.selectedLocalFiles) ? (React.createElement(React.Fragment, null,
171
- React.createElement("div", { role: "alert", className: "submit-page-title pf-v5-u-mb-lg" },
171
+ React.createElement("div", { className: "submit-page-title pf-v5-u-mb-lg" },
172
172
  React.createElement(Icon, { className: "submit-case-check-icon pf-v5-u-mt-sm", size: "lg" },
173
173
  React.createElement(CheckCircleIcon, null)),
174
174
  ' ',
175
- React.createElement(Text, { className: "pf-v5-u-mb-0", component: TextVariants.h1 },
175
+ React.createElement(Text, { role: "alert", className: "pf-v5-u-mb-0", component: TextVariants.h1 },
176
176
  React.createElement(Trans, null, "We've added your case to our queue"))),
177
177
  React.createElement("div", { className: "pf-v5-u-mt-sm" },
178
178
  React.createElement(Trans, null, "Case number:"),
@@ -184,7 +184,7 @@ export default function SubmitCase(props) {
184
184
  React.createElement(Icon, { size: "lg", className: "submit-case-check-icon" },
185
185
  React.createElement(CheckCircleIcon, null)),
186
186
  ' ',
187
- React.createElement(Text, { component: TextVariants.h1 },
187
+ React.createElement(Text, { role: "alert", component: TextVariants.h1 },
188
188
  React.createElement(Trans, null, "We\u2019ve added your case to our queue"))),
189
189
  React.createElement(React.Fragment, null,
190
190
  React.createElement(Trans, null, "Case number: "),
@@ -1009,7 +1009,8 @@ svg.pf-v5-u-ml-xs.icon-size {
1009
1009
  }
1010
1010
 
1011
1011
  .case-internal-status-selector-text,
1012
- .get-support-severity-modal-text {
1012
+ .get-support-severity-modal-text,
1013
+ .case-type-selector-text {
1013
1014
  .pf-v5-c-menu-toggle__text {
1014
1015
  width: 100%;
1015
1016
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rh-support/troubleshoot",
3
- "version": "2.2.185",
3
+ "version": "2.2.187",
4
4
  "publishConfig": {
5
5
  "access": "public",
6
6
  "registry": "https://registry.npmjs.org"
@@ -25,7 +25,7 @@
25
25
  "lib/**/*"
26
26
  ],
27
27
  "peerDependencies": {
28
- "@cee-eng/hydrajs": "4.17.26",
28
+ "@cee-eng/hydrajs": "4.17.27",
29
29
  "@cee-eng/ui-toolkit": "1.1.8",
30
30
  "@patternfly/patternfly": "5.4.0",
31
31
  "@patternfly/react-core": "5.4.0",
@@ -51,7 +51,7 @@
51
51
  "react-virtualized": "^9.22.5"
52
52
  },
53
53
  "dependencies": {
54
- "@cee-eng/hydrajs": "4.17.26",
54
+ "@cee-eng/hydrajs": "4.17.27",
55
55
  "@cee-eng/ui-toolkit": "1.1.8",
56
56
  "@patternfly/patternfly": "5.4.0",
57
57
  "@patternfly/react-core": "5.4.0",
@@ -60,11 +60,11 @@
60
60
  "@progress/kendo-licensing": "1.3.5",
61
61
  "@progress/kendo-react-pdf": "^5.16.0",
62
62
  "@redux-devtools/extension": "^3.3.0",
63
- "@rh-support/components": "2.1.88",
64
- "@rh-support/react-context": "2.1.97",
63
+ "@rh-support/components": "2.1.89",
64
+ "@rh-support/react-context": "2.1.98",
65
65
  "@rh-support/types": "2.0.5",
66
- "@rh-support/user-permissions": "2.1.53",
67
- "@rh-support/utils": "2.1.42",
66
+ "@rh-support/user-permissions": "2.1.54",
67
+ "@rh-support/utils": "2.1.43",
68
68
  "@types/react-redux": "^7.1.33",
69
69
  "@types/redux": "^3.6.0",
70
70
  "dompurify": "^2.2.6",
@@ -133,5 +133,5 @@
133
133
  "defaults and supports es6-module",
134
134
  "maintained node versions"
135
135
  ],
136
- "gitHead": "bb681f529a71f7b3de7f9cfb3a579b1a42eefd3e"
136
+ "gitHead": "4e0f1c9e7374499fb86580de1165f97eab93c7f3"
137
137
  }