@rh-support/troubleshoot 2.6.357 → 2.6.361

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 (132) hide show
  1. package/lib/esm/components/AccountInfo/OwnerSelector.js +5 -5
  2. package/lib/esm/components/CaseEditView/CaseDetailsErrorMessage.d.ts.map +1 -1
  3. package/lib/esm/components/CaseEditView/CaseDetailsErrorMessage.js +16 -6
  4. package/lib/esm/components/CaseEditView/CaseDetailsTabs.d.ts.map +1 -1
  5. package/lib/esm/components/CaseEditView/CaseDetailsTabs.js +11 -7
  6. package/lib/esm/components/CaseEditView/CaseOverview/CaseStatus.d.ts +2 -0
  7. package/lib/esm/components/CaseEditView/CaseOverview/CaseStatus.d.ts.map +1 -1
  8. package/lib/esm/components/CaseEditView/CaseOverview/CaseStatus.js +19 -8
  9. package/lib/esm/components/CaseEditView/CaseOverview/index.d.ts.map +1 -1
  10. package/lib/esm/components/CaseEditView/CaseOverview/index.js +23 -19
  11. package/lib/esm/components/CaseEditView/CaseSolutions/CaseSolutions.d.ts.map +1 -1
  12. package/lib/esm/components/CaseEditView/CaseSolutions/CaseSolutions.js +1 -1
  13. package/lib/esm/components/CaseEditView/ConfirmationModals/ReopenCaseModal.js +2 -2
  14. package/lib/esm/components/CaseEditView/RequestRemoteSession/NewEssTermsModal.d.ts.map +1 -1
  15. package/lib/esm/components/CaseEditView/RequestRemoteSession/NewEssTermsModal.js +7 -5
  16. package/lib/esm/components/CaseEditView/RequestRemoteSession/RemoteSessionAgreementModal.d.ts.map +1 -1
  17. package/lib/esm/components/CaseEditView/RequestRemoteSession/RemoteSessionAgreementModal.js +7 -5
  18. package/lib/esm/components/CaseEditView/RequestRemoteSession/remoteSessionUtils.d.ts +6 -0
  19. package/lib/esm/components/CaseEditView/RequestRemoteSession/remoteSessionUtils.d.ts.map +1 -1
  20. package/lib/esm/components/CaseEditView/RequestRemoteSession/remoteSessionUtils.js +8 -0
  21. package/lib/esm/components/CaseEditView/Tabs/CaseActionPlan/CaseActionPlan.d.ts.map +1 -1
  22. package/lib/esm/components/CaseEditView/Tabs/CaseActionPlan/CaseActionPlan.js +6 -3
  23. package/lib/esm/components/CaseEditView/Tabs/CaseDetails/CaseContactPhoneNumber.js +1 -1
  24. package/lib/esm/components/CaseEditView/Tabs/CaseDetails/CaseDetailsManagement.d.ts.map +1 -1
  25. package/lib/esm/components/CaseEditView/Tabs/CaseDetails/CaseDetailsManagement.js +41 -8
  26. package/lib/esm/components/CaseEditView/Tabs/CaseDetails/CaseHostname.js +1 -1
  27. package/lib/esm/components/CaseEditView/Tabs/CaseDetails/CaseInternalStatus.js +1 -1
  28. package/lib/esm/components/CaseEditView/Tabs/CaseDetails/CaseOpenshiftClusterId/CaseOpenshiftClusterId.d.ts.map +1 -1
  29. package/lib/esm/components/CaseEditView/Tabs/CaseDetails/CaseOpenshiftClusterId/CaseOpenshiftClusterId.js +11 -11
  30. package/lib/esm/components/CaseEditView/Tabs/CaseDetails/CasePhoneNumberConfirmAlert.js +1 -1
  31. package/lib/esm/components/CaseEditView/Tabs/CaseDetails/CaseReferenceNumber.js +1 -1
  32. package/lib/esm/components/CaseEditView/Tabs/CaseDetails/CaseSbrGroups.d.ts.map +1 -1
  33. package/lib/esm/components/CaseEditView/Tabs/CaseDetails/CaseSbrGroups.js +3 -1
  34. package/lib/esm/components/CaseEditView/Tabs/CaseDetails/ProductVersion.d.ts.map +1 -1
  35. package/lib/esm/components/CaseEditView/Tabs/CaseDetails/ProductVersion.js +1 -6
  36. package/lib/esm/components/CaseEditView/Tabs/CaseDetails/Summary.js +1 -1
  37. package/lib/esm/components/CaseEditView/Tabs/CaseDetails/useCustomEmails.d.ts.map +1 -1
  38. package/lib/esm/components/CaseEditView/Tabs/CaseDetails/useCustomEmails.js +4 -2
  39. package/lib/esm/components/CaseEditView/Tabs/CaseDiscussion/CaseAttachment.d.ts.map +1 -1
  40. package/lib/esm/components/CaseEditView/Tabs/CaseDiscussion/CaseAttachment.js +5 -3
  41. package/lib/esm/components/CaseEditView/Tabs/CaseDiscussion/CaseComments.d.ts.map +1 -1
  42. package/lib/esm/components/CaseEditView/Tabs/CaseDiscussion/CaseComments.js +33 -3
  43. package/lib/esm/components/CaseEditView/Tabs/CaseDiscussion/CaseDiscussion.d.ts +6 -0
  44. package/lib/esm/components/CaseEditView/Tabs/CaseDiscussion/CaseDiscussion.d.ts.map +1 -1
  45. package/lib/esm/components/CaseEditView/Tabs/CaseDiscussion/CaseDiscussion.js +210 -35
  46. package/lib/esm/components/CaseEditView/Tabs/CaseDiscussion/PostComment/useCommentDrafts.d.ts +1 -1
  47. package/lib/esm/components/CaseEditView/Tabs/CaseDiscussion/PostComment/useCommentDrafts.d.ts.map +1 -1
  48. package/lib/esm/components/CaseEditView/Tabs/CaseDiscussion/PostComment/useCommentDrafts.js +3 -1
  49. package/lib/esm/components/CaseEditView/Tabs/CaseDiscussion/PostComment.d.ts.map +1 -1
  50. package/lib/esm/components/CaseEditView/Tabs/CaseDiscussion/PostComment.js +11 -17
  51. package/lib/esm/components/CaseEditView/Tabs/CaseDiscussion/VerifyCaseStatusModal/VerifyCaseStatusModal.d.ts.map +1 -1
  52. package/lib/esm/components/CaseEditView/Tabs/CaseDiscussion/VerifyCaseStatusModal/VerifyCaseStatusModal.js +1 -1
  53. package/lib/esm/components/CaseEditView/Tabs/CaseHistory/CaseHistory.d.ts.map +1 -1
  54. package/lib/esm/components/CaseEditView/Tabs/CaseHistory/CaseHistory.js +5 -2
  55. package/lib/esm/components/CaseEditView/Tabs/CaseHistory/Timeline.d.ts +2 -1
  56. package/lib/esm/components/CaseEditView/Tabs/CaseHistory/Timeline.d.ts.map +1 -1
  57. package/lib/esm/components/CaseEditView/Tabs/CaseHistory/Timeline.js +4 -11
  58. package/lib/esm/components/CaseEditView/Tabs/CasePrivateNotes/CasePrivateNotes.d.ts.map +1 -1
  59. package/lib/esm/components/CaseEditView/Tabs/CasePrivateNotes/CasePrivateNotes.js +6 -3
  60. package/lib/esm/components/CaseEditView/Tabs/CaseSummary/CaseSummary.d.ts.map +1 -1
  61. package/lib/esm/components/CaseEditView/Tabs/CaseSummary/CaseSummary.js +1 -0
  62. package/lib/esm/components/CaseInformation/CaseGroup.d.ts.map +1 -1
  63. package/lib/esm/components/CaseInformation/CaseGroup.js +6 -2
  64. package/lib/esm/components/CaseInformation/CaseLabels.d.ts.map +1 -1
  65. package/lib/esm/components/CaseInformation/CaseLabels.js +21 -16
  66. package/lib/esm/components/CaseInformation/Fts.js +2 -2
  67. package/lib/esm/components/CaseInformation/Severity.d.ts.map +1 -1
  68. package/lib/esm/components/CaseInformation/Severity.js +16 -15
  69. package/lib/esm/components/CaseManagement/CaseLabelsCreate.d.ts.map +1 -1
  70. package/lib/esm/components/CaseManagement/CaseLabelsCreate.js +52 -21
  71. package/lib/esm/components/CaseManagement/Cep.js +1 -1
  72. package/lib/esm/components/CaseManagement/NoClusterIDReasonSelector.d.ts.map +1 -1
  73. package/lib/esm/components/CaseManagement/NoClusterIDReasonSelector.js +1 -3
  74. package/lib/esm/components/CaseManagement/OpenShiftClusterId.d.ts.map +1 -1
  75. package/lib/esm/components/CaseManagement/OpenShiftClusterId.js +1 -1
  76. package/lib/esm/components/CaseManagement/OpenshiftDropdownV4.d.ts +0 -1
  77. package/lib/esm/components/CaseManagement/OpenshiftDropdownV4.d.ts.map +1 -1
  78. package/lib/esm/components/CaseManagement/OpenshiftDropdownV4.js +6 -12
  79. package/lib/esm/components/CaseManagement/RHAssociatesSelector.d.ts.map +1 -1
  80. package/lib/esm/components/CaseManagement/RHAssociatesSelector.js +4 -2
  81. package/lib/esm/components/CaseManagement/SendNotifications/CaseContactSelector.d.ts.map +1 -1
  82. package/lib/esm/components/CaseManagement/SendNotifications/CaseContactSelector.js +4 -2
  83. package/lib/esm/components/EditDescription/EditDescription.d.ts.map +1 -1
  84. package/lib/esm/components/EditDescription/EditDescription.js +3 -1
  85. package/lib/esm/components/IdeaInformation/IdeaInformation.d.ts.map +1 -1
  86. package/lib/esm/components/IdeaInformation/IdeaInformation.js +11 -3
  87. package/lib/esm/components/UpdateSeverityModal/UpdateSeverityModal.d.ts.map +1 -1
  88. package/lib/esm/components/UpdateSeverityModal/UpdateSeverityModal.js +52 -46
  89. package/lib/esm/components/shared/fileUpload/reducer/AttachmentHelper.d.ts +1 -0
  90. package/lib/esm/components/shared/fileUpload/reducer/AttachmentHelper.d.ts.map +1 -1
  91. package/lib/esm/components/shared/fileUpload/reducer/AttachmentHelper.js +126 -54
  92. package/lib/esm/components/shared/fileUpload/useFileUploader.d.ts.map +1 -1
  93. package/lib/esm/components/shared/fileUpload/useFileUploader.js +6 -3
  94. package/lib/esm/components/wizardLayout/MainSection.d.ts.map +1 -1
  95. package/lib/esm/components/wizardLayout/MainSection.js +2 -1
  96. package/lib/esm/css/case.css +154 -8
  97. package/lib/esm/graphql/queries/getEscalationDetails.d.ts.map +1 -1
  98. package/lib/esm/graphql/queries/getEscalationDetails.js +5 -0
  99. package/lib/esm/hooks/useCaseComments/caseCommentsQuery.d.ts.map +1 -1
  100. package/lib/esm/hooks/useCaseComments/caseCommentsQuery.js +6 -1
  101. package/lib/esm/hooks/useCaseComments/index.d.ts +2 -1
  102. package/lib/esm/hooks/useCaseComments/index.d.ts.map +1 -1
  103. package/lib/esm/hooks/useCaseComments/types.d.ts +8 -0
  104. package/lib/esm/hooks/useCaseComments/types.d.ts.map +1 -1
  105. package/lib/esm/hooks/useCaseComments/useCaseComments.d.ts +12 -3
  106. package/lib/esm/hooks/useCaseComments/useCaseComments.d.ts.map +1 -1
  107. package/lib/esm/hooks/useCaseComments/useCaseComments.js +84 -9
  108. package/lib/esm/hooks/useCaseHistory.d.ts +2 -2
  109. package/lib/esm/hooks/useCaseHistory.d.ts.map +1 -1
  110. package/lib/esm/hooks/useCaseHistory.js +16 -7
  111. package/lib/esm/hooks/useCaseLabelLinkMutations.d.ts +2 -0
  112. package/lib/esm/hooks/useCaseLabelLinkMutations.d.ts.map +1 -1
  113. package/lib/esm/hooks/useCaseLabelLinkMutations.js +21 -28
  114. package/lib/esm/hooks/useCaseUpdateErrorMessage.d.ts +9 -1
  115. package/lib/esm/hooks/useCaseUpdateErrorMessage.d.ts.map +1 -1
  116. package/lib/esm/hooks/useCaseUpdateErrorMessage.js +103 -16
  117. package/lib/esm/models/caseHistory.d.ts +6 -0
  118. package/lib/esm/models/caseHistory.d.ts.map +1 -1
  119. package/lib/esm/reducers/CaseDiscussionTabReducer.d.ts +2 -1
  120. package/lib/esm/reducers/CaseDiscussionTabReducer.d.ts.map +1 -1
  121. package/lib/esm/reducers/CaseDiscussionTabReducer.js +26 -4
  122. package/lib/esm/reducers/CaseHelpers.d.ts.map +1 -1
  123. package/lib/esm/reducers/CaseHelpers.js +5 -3
  124. package/lib/esm/reducers/CaseReducer.d.ts.map +1 -1
  125. package/lib/esm/reducers/CaseReducer.js +6 -2
  126. package/lib/esm/utils/caseHistoryUtils.d.ts +19 -0
  127. package/lib/esm/utils/caseHistoryUtils.d.ts.map +1 -1
  128. package/lib/esm/utils/caseHistoryUtils.js +31 -0
  129. package/lib/esm/utils/linkifyHtmlTextNodes.d.ts +8 -0
  130. package/lib/esm/utils/linkifyHtmlTextNodes.d.ts.map +1 -0
  131. package/lib/esm/utils/linkifyHtmlTextNodes.js +37 -0
  132. package/package.json +7 -6
@@ -34,7 +34,7 @@ function getOwnerDropdownOptions(contacts) {
34
34
  function OwnerSelector(props) {
35
35
  const { t } = useTranslation();
36
36
  const caseUpdateError = useCaseUpdateErrorMessage();
37
- const { accountNumber, caseNumber, contactSsoUsername, existingCaseDetails, selectedNotificationContacts, selectedOwner, selectedCaseGroupUsers, selectedAccountDetails, isCaseOwnerUpdating, isCasePhoneUpdating, groupNumber, } = useCaseSelector((state) => ({
37
+ const { accountNumber, caseNumber, contactSsoUsername, existingCaseDetails, selectedNotificationContacts, selectedOwner, selectedCaseGroupUsers, selectedAccountDetails, isCaseOwnerUpdating, isCasePhoneUpdating, } = useCaseSelector((state) => ({
38
38
  accountNumber: state.caseDetails.accountNumberRef,
39
39
  caseNumber: state.caseDetails.caseNumber,
40
40
  existingCaseDetails: state.caseDetails,
@@ -45,7 +45,6 @@ function OwnerSelector(props) {
45
45
  isCaseOwnerUpdating: state.isCaseOwnerUpdating,
46
46
  isCasePhoneUpdating: state.isCasePhoneUpdating,
47
47
  contactSsoUsername: state.caseDetails.contactSSOName,
48
- groupNumber: state.caseDetails.groupNumber,
49
48
  }), isEqual);
50
49
  const { routeState: { isNextBtnClickedToShowValidationError }, } = useContext(RouteContext);
51
50
  const caseDispatch = useCaseDispatch();
@@ -192,7 +191,7 @@ function OwnerSelector(props) {
192
191
  }
193
192
  catch (e) {
194
193
  setCaseState(caseDispatch, { isCaseOwnerUpdating: false });
195
- caseUpdateError.showError(e, t(`Owner failed to update`));
194
+ caseUpdateError.showFieldError(e, t('Owner'), () => onCaseOwnerUpdate(newOwner));
196
195
  }
197
196
  });
198
197
  /**
@@ -281,9 +280,10 @@ function OwnerSelector(props) {
281
280
  setCaseState(caseDispatch, {
282
281
  selectedOwner: { data: contact, isFetching: false, isError: false, errorMessage: '' },
283
282
  });
284
- if (contact.id && accountNumber) {
285
- fetchCaseGroupsForContactGraphQL(caseDispatch, apolloClient, contact.id, accountNumber, (_a = contact.defaultCaseGroup) !== null && _a !== void 0 ? _a : null, (_b = contact.isOrgAdmin) !== null && _b !== void 0 ? _b : false, caseNumber ? groupNumber : groupNumber || null);
283
+ if (!contact.id || !accountNumber || caseNumber) {
284
+ return;
286
285
  }
286
+ fetchCaseGroupsForContactGraphQL(caseDispatch, apolloClient, contact.id, accountNumber, (_a = contact.defaultCaseGroup) !== null && _a !== void 0 ? _a : null, (_b = contact.isOrgAdmin) !== null && _b !== void 0 ? _b : false, null);
287
287
  }, placeholder: t(`Search by name or username`), clearButton: true, id: "get-support-owner", name: "get-support-owner", className: "react-select-custom", isUpdating: isCaseOwnerUpdating, isInvalid: isNextBtnClickedToShowValidationError && isEmpty(selectedOwner.data), isDisabled: isCasePhoneUpdating || isCaseOwnerUpdating || canEditCase.isCaseNotEditable }))));
288
288
  }
289
289
  export { OwnerSelector };
@@ -1 +1 @@
1
- {"version":3,"file":"CaseDetailsErrorMessage.d.ts","sourceRoot":"","sources":["../../../../src/components/CaseEditView/CaseDetailsErrorMessage.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAErD,OAAO,KAAqB,MAAM,OAAO,CAAC;AAG1C,UAAU,MAAM;IACZ,OAAO,EAAE,OAAO,CAAC;IACjB,YAAY,EAAE,SAAS,CAAC;IACxB,WAAW,EAAE,OAAO,CAAC;IACrB,aAAa,EAAE,OAAO,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,OAAO,CAAC;CAC3B;AAID,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,MAAM,qBA4FpD"}
1
+ {"version":3,"file":"CaseDetailsErrorMessage.d.ts","sourceRoot":"","sources":["../../../../src/components/CaseEditView/CaseDetailsErrorMessage.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAErD,OAAO,KAAqB,MAAM,OAAO,CAAC;AAG1C,UAAU,MAAM;IACZ,OAAO,EAAE,OAAO,CAAC;IACjB,YAAY,EAAE,SAAS,CAAC;IACxB,WAAW,EAAE,OAAO,CAAC;IACrB,aAAa,EAAE,OAAO,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,OAAO,CAAC;CAC3B;AAKD,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,MAAM,qBA0GpD"}
@@ -1,10 +1,11 @@
1
1
  import { AlertMessage, AlertType, errorMessageTitle, formattedApiErrorMessage } from '@rh-support/components';
2
2
  import { GlobalMetadataStateContext } from '@rh-support/react-context';
3
- import { CSS_ACCESS_RESTRICTION_ERROR_DETAIL, CSS_PORTAL_URL, getSFDCSecureSupportCaseLink } from '@rh-support/utils';
3
+ import { CSS_ACCESS_RESTRICTION_ERROR_DETAIL, getCssPortalUrl, getSFDCSecureSupportCaseLink } from '@rh-support/utils';
4
4
  import React, { useContext } from 'react';
5
5
  import { Trans, useTranslation } from 'react-i18next';
6
6
  // Here we need to use 'detailMessage' from case API if user is not authorized to see case detail
7
7
  const INVALID_CASE_GROUP_API_ERROR_DEFAULT_MESSAGE = 'Invalid group access';
8
+ const NO_PERMISSION_PATTERN = /do not have permission|not authorized|don't have permission/i;
8
9
  export function CaseDetailsErrorMessage(props) {
9
10
  const { globalMetadataState: { loggedInUserRights }, } = useContext(GlobalMetadataStateContext);
10
11
  const { t } = useTranslation();
@@ -18,18 +19,25 @@ export function CaseDetailsErrorMessage(props) {
18
19
  */
19
20
  const isCaseGroupError = (errorDetails === null || errorDetails === void 0 ? void 0 : errorDetails['detailMessage']) === INVALID_CASE_GROUP_API_ERROR_DEFAULT_MESSAGE;
20
21
  const isCssAccessRestrictionError = (errorDetails === null || errorDetails === void 0 ? void 0 : errorDetails['detailMessage']) === CSS_ACCESS_RESTRICTION_ERROR_DETAIL;
22
+ const rawErrorMessage = [errorDetails === null || errorDetails === void 0 ? void 0 : errorDetails['message'], errorDetails === null || errorDetails === void 0 ? void 0 : errorDetails['detailMessage']].filter(Boolean).join(' ');
23
+ const isUnauthorizedAccessError = !isCaseGroupError && !isCssAccessRestrictionError && NO_PERMISSION_PATTERN.test(rawErrorMessage);
24
+ const unauthorizedAccessTitle = t('You do not have permission to view this case');
21
25
  const getErrorMessage = () => {
22
26
  const { status, message = '' } = errorDetails || {};
23
- const customDefaultErrorMessage403 = isCaseGroupError
24
- ? t('Please contact your organization’s admin to request access to this case’s group.')
25
- : t('You are not authorized to see this case.');
27
+ let customDefaultErrorMessage403 = t('You are not authorized to see this case.');
28
+ if (isCaseGroupError) {
29
+ customDefaultErrorMessage403 = t('Please contact your organization’s admin to request access to this case’s group.');
30
+ }
31
+ else if (isUnauthorizedAccessError) {
32
+ customDefaultErrorMessage403 = t('You do not have permission to view this case. Please contact your organization administrator if you believe you should have access.');
33
+ }
26
34
  const errorMessage404 = t("Case number doesn't exist");
27
35
  let errorMessage403;
28
36
  if (isCssAccessRestrictionError) {
29
37
  errorMessage403 = (React.createElement(React.Fragment, null,
30
38
  "Open this case in the",
31
39
  ' ',
32
- React.createElement("a", { href: CSS_PORTAL_URL, "data-tracking-id": "css-access-restriction-portal-redirect" }, "Confirmed Sovereign Support portal"),
40
+ React.createElement("a", { href: getCssPortalUrl(), "data-tracking-id": "css-access-restriction-portal-redirect" }, "Confirmed Sovereign Support portal"),
33
41
  "."));
34
42
  }
35
43
  else if (!canReadCase) {
@@ -57,10 +65,12 @@ export function CaseDetailsErrorMessage(props) {
57
65
  };
58
66
  return (React.createElement(AlertMessage, { variant: AlertType.DANGER, className: "pf-v6-u-mb-lg", show: true,
59
67
  // Here customizing title of alert based on case group error.
60
- title: errorMessageTitle(errorDetails, Object.assign(Object.assign({}, (isCaseGroupError && {
68
+ title: errorMessageTitle(errorDetails, Object.assign(Object.assign(Object.assign({}, (isCaseGroupError && {
61
69
  '403': { title: invalidCaseGroupErrorTitle },
62
70
  })), (isCssAccessRestrictionError && {
63
71
  '403': { title: cssAccessRestrictionErrorTitle },
72
+ })), (isUnauthorizedAccessError && {
73
+ '403': { title: unauthorizedAccessTitle },
64
74
  })), canManageCase), isInline: isInlineError },
65
75
  React.createElement(Trans, null, getErrorMessage())));
66
76
  }
@@ -1 +1 @@
1
- {"version":3,"file":"CaseDetailsTabs.d.ts","sourceRoot":"","sources":["../../../../src/components/CaseEditView/CaseDetailsTabs.tsx"],"names":[],"mappings":"AAkBA,OAAO,KAAiD,MAAM,OAAO,CAAC;AAEtE,OAAO,EAAE,mBAAmB,EAAa,MAAM,kBAAkB,CAAC;AA8BlE,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,qBAoT5C"}
1
+ {"version":3,"file":"CaseDetailsTabs.d.ts","sourceRoot":"","sources":["../../../../src/components/CaseEditView/CaseDetailsTabs.tsx"],"names":[],"mappings":"AAkBA,OAAO,KAAiD,MAAM,OAAO,CAAC;AAEtE,OAAO,EAAE,mBAAmB,EAA0B,MAAM,kBAAkB,CAAC;AA+B/E,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,qBA0U5C"}
@@ -4,14 +4,15 @@ import InfoCircleIcon from '@patternfly/react-icons/dist/js/icons/info-circle-ic
4
4
  import { ErrorBoundary, LoadingIndicator } from '@rh-support/components';
5
5
  import { GlobalMetadataStateContext } from '@rh-support/react-context';
6
6
  import { ability, CaseDetailsFields, resourceActions, resources } from '@rh-support/user-permissions';
7
- import { getConfigField, PCM_CONFIG_FIELD_TYPE } from '@rh-support/utils';
7
+ import { getConfigField, getUrlParsedParams, PCM_CONFIG_FIELD_TYPE } from '@rh-support/utils';
8
8
  import isEqual from 'lodash/isEqual';
9
9
  import React, { Suspense, useContext, useRef, useState } from 'react';
10
10
  import { Trans, useTranslation } from 'react-i18next';
11
- import { useParams } from 'react-router-dom';
11
+ import { useLocation, useParams } from 'react-router-dom';
12
12
  import { CaseDetailsTabsEnum } from '../../constants/caseDetailsConstants';
13
13
  import { useCaseSelector } from '../../context/CaseContext';
14
14
  import { useCaseDetailsPageStateContext } from '../../context/CaseDetailsPageContext';
15
+ import { useCaseDiscussionTabStateContext } from '../../context/CaseDiscussionTabContext';
15
16
  import { useCaseComments } from '../../hooks/useCaseComments';
16
17
  import { PDFContext } from './PDFContainer';
17
18
  import CaseDetailsManagement from './Tabs/CaseDetails/CaseDetailsManagement';
@@ -44,10 +45,13 @@ export function CaseDetailsTabs(props) {
44
45
  privateNotes: (_a = state.caseDetails.notes) !== null && _a !== void 0 ? _a : '',
45
46
  });
46
47
  }, isEqual);
47
- const { comments, loading: commentsLoading, error: commentsError, refetch: refetchComments, } = useCaseComments({
48
- caseId: caseSalesforceId,
49
- skip: !caseSalesforceId,
50
- });
48
+ const urlSearchParams = getUrlParsedParams(useLocation().search);
49
+ const deepLinkCommentId = ((urlSearchParams === null || urlSearchParams === void 0 ? void 0 : urlSearchParams.commentId) || (urlSearchParams === null || urlSearchParams === void 0 ? void 0 : urlSearchParams.attachmentId));
50
+ const { sort: discussionSort } = useCaseDiscussionTabStateContext();
51
+ const graphqlOrderBy = {
52
+ LastModifiedDate: { order: discussionSort.sortOrder === 'asc' ? 'ASC' : 'DESC' },
53
+ };
54
+ const { comments, loading: commentsLoading, error: commentsError, refetch: refetchComments, fetchMore, hasNextPage, isLoadingMore, loadMoreError, loadMoreRetryCount, retryLoadMore, } = useCaseComments(Object.assign({ caseId: caseSalesforceId, skip: !caseSalesforceId, orderBy: graphqlOrderBy }, (deepLinkCommentId ? { first: 2000 } : {})));
51
55
  const { t } = useTranslation();
52
56
  const [activeTabKey, setActiveTabKey] = useState(0);
53
57
  const { caseDetailsPageState: { caseEscalations }, } = useCaseDetailsPageStateContext();
@@ -94,7 +98,7 @@ export function CaseDetailsTabs(props) {
94
98
  component: (React.createElement(CaseDiscussion, { caseNumber: caseNumber, tabRef: discussionTabRef, caseComments: comments, commentsLoading: commentsLoading, commentsError: commentsError,
95
99
  // TODO: Re-enable after GraphQL migration of chats
96
100
  // caseChats={chats}
97
- accountNumber: accountNumber, isDiscussionTab: selectedTab === CaseDetailsTabsEnum.DISCUSSION, refetchComments: refetchComments })),
101
+ accountNumber: accountNumber, isDiscussionTab: selectedTab === CaseDetailsTabsEnum.DISCUSSION, refetchComments: refetchComments, fetchMore: fetchMore, hasNextPage: hasNextPage, isLoadingMore: isLoadingMore, loadMoreError: loadMoreError, loadMoreRetryCount: loadMoreRetryCount, retryLoadMore: retryLoadMore })),
98
102
  });
99
103
  tabsToRender.push({
100
104
  'data-tracking-id': 'case-details-tab',
@@ -6,6 +6,8 @@ interface IProps extends IDClassNameProps {
6
6
  isDisabled: boolean;
7
7
  isFetching: boolean;
8
8
  hasError: boolean;
9
+ isClosed: boolean;
10
+ isInternal: boolean;
9
11
  }
10
12
  declare function CaseStatus(props: IProps): React.JSX.Element;
11
13
  declare namespace CaseStatus {
@@ -1 +1 @@
1
- {"version":3,"file":"CaseStatus.d.ts","sourceRoot":"","sources":["../../../../../src/components/CaseEditView/CaseOverview/CaseStatus.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAI5D,OAAO,KAAwC,MAAM,OAAO,CAAC;AAO7D,UAAU,MAAO,SAAQ,gBAAgB;IACrC,cAAc,EAAE,MAAM,CAAC;IACvB,cAAc,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/D,UAAU,EAAE,OAAO,CAAC;IACpB,UAAU,EAAE,OAAO,CAAC;IACpB,QAAQ,EAAE,OAAO,CAAC;CACrB;AAOD,iBAAS,UAAU,CAAC,KAAK,EAAE,MAAM,qBAmEhC;kBAnEQ,UAAU;;;AAsEnB,eAAe,UAAU,CAAC"}
1
+ {"version":3,"file":"CaseStatus.d.ts","sourceRoot":"","sources":["../../../../../src/components/CaseEditView/CaseOverview/CaseStatus.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAI5D,OAAO,KAAwC,MAAM,OAAO,CAAC;AAO7D,UAAU,MAAO,SAAQ,gBAAgB;IACrC,cAAc,EAAE,MAAM,CAAC;IACvB,cAAc,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/D,UAAU,EAAE,OAAO,CAAC;IACpB,UAAU,EAAE,OAAO,CAAC;IACpB,QAAQ,EAAE,OAAO,CAAC;IAClB,QAAQ,EAAE,OAAO,CAAC;IAClB,UAAU,EAAE,OAAO,CAAC;CACvB;AAgBD,iBAAS,UAAU,CAAC,KAAK,EAAE,MAAM,qBAwEhC;kBAxEQ,UAAU;;;AA2EnB,eAAe,UAAU,CAAC"}
@@ -8,9 +8,9 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
8
8
  });
9
9
  };
10
10
  import { SingleSelectDropdown, ValueChangedIcon } from '@rh-support/components';
11
- import { mapSfdcStatusToPortalStatus, PORTAL_USER_SELECTABLE_STATUSES } from '@rh-support/utils';
11
+ import { getPortalStatusDropdownOptions, mapSfdcStatusToPortalStatus } from '@rh-support/utils';
12
+ import i18next from 'i18next';
12
13
  import isEmpty from 'lodash/isEmpty';
13
- import map from 'lodash/map';
14
14
  import React, { useContext, useMemo, useState } from 'react';
15
15
  import { Trans, useTranslation } from 'react-i18next';
16
16
  import { CaseValuesToWatch } from '../../shared/Constants';
@@ -20,6 +20,14 @@ const defaultProps = {
20
20
  id: '',
21
21
  className: '',
22
22
  };
23
+ const STATUS_DESCRIPTIONS = {
24
+ get restricted() {
25
+ return i18next.t('Only Red Hat Support can set this status');
26
+ },
27
+ get closed() {
28
+ return i18next.t('Use In Progress to reopen this case');
29
+ },
30
+ };
23
31
  function CaseStatus(props) {
24
32
  const { t } = useTranslation();
25
33
  const [isCaseStatusInValid, setIsCaseStatusInValid] = useState(false);
@@ -28,21 +36,24 @@ function CaseStatus(props) {
28
36
  };
29
37
  const { isExportingPDF } = useContext(PDFContext);
30
38
  const selectedPortalStatus = useMemo(() => mapSfdcStatusToPortalStatus(props.selectedStatus), [props.selectedStatus]);
31
- // value changed logic to show a non local status change
32
39
  const [localStatusChange, setLocalStatusChange] = useState(false);
33
40
  const afterLocalChange = () => setLocalStatusChange(false);
34
41
  const onCaseStatusChange = (option) => __awaiter(this, void 0, void 0, function* () {
35
- if (option.value === selectedPortalStatus) {
42
+ if (option.disabled || option.value === selectedPortalStatus) {
36
43
  return;
37
44
  }
38
45
  yield props.onStatusChange(option.value);
39
46
  setLocalStatusChange(true);
40
47
  validateCaseStatus(option);
41
48
  });
42
- const getDropdownOptions = map(PORTAL_USER_SELECTABLE_STATUSES, (option) => ({
43
- label: option,
44
- value: option,
45
- }));
49
+ const statusOptions = getPortalStatusDropdownOptions(props.isClosed, props.isInternal);
50
+ const getDropdownOptions = statusOptions.map((opt) => {
51
+ let description;
52
+ if (opt.disabled) {
53
+ description = opt.value === 'Closed' ? STATUS_DESCRIPTIONS.closed : STATUS_DESCRIPTIONS.restricted;
54
+ }
55
+ return Object.assign({ label: opt.value, value: opt.value, disabled: opt.disabled }, (description ? { description } : {}));
56
+ });
46
57
  const getSelectedDropdownOption = {
47
58
  label: selectedPortalStatus,
48
59
  value: selectedPortalStatus,
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/components/CaseEditView/CaseOverview/index.tsx"],"names":[],"mappings":"AAmCA,OAAO,KAAkD,MAAM,OAAO,CAAC;AA4BvE,UAAU,MAAM;IACZ,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,KAAK,CAAC,gBAAgB,CAAC,cAAc,CAAC,CAAC;CACnD;AAED,MAAM,CAAC,OAAO,UAAU,YAAY,CAAC,KAAK,EAAE,MAAM,qBAujBjD"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/components/CaseEditView/CaseOverview/index.tsx"],"names":[],"mappings":"AAmCA,OAAO,KAAkD,MAAM,OAAO,CAAC;AA4BvE,UAAU,MAAM;IACZ,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,KAAK,CAAC,gBAAgB,CAAC,cAAc,CAAC,CAAC;CACnD;AAED,MAAM,CAAC,OAAO,UAAU,YAAY,CAAC,KAAK,EAAE,MAAM,qBAqkBjD"}
@@ -132,7 +132,19 @@ export default function CaseOverview(props) {
132
132
  }
133
133
  catch (e) {
134
134
  setTypeUpdating(caseOverviewDispatch, false);
135
- caseUpdateError.showError(e, t('Support type failed to update'));
135
+ caseUpdateError.showFieldError(e, t('Support type'), () => onTypeChange(type));
136
+ }
137
+ });
138
+ const applySeverityUpdate = (payLoad) => __awaiter(this, void 0, void 0, function* () {
139
+ setSeverityUpdating(caseOverviewDispatch, true);
140
+ try {
141
+ yield updateOverviewCaseDetails(payLoad);
142
+ setSeverityUpdating(caseOverviewDispatch, false);
143
+ ToastNotification.addSuccessMessage(t('Severity has been successfully updated'));
144
+ }
145
+ catch (e) {
146
+ setSeverityUpdating(caseOverviewDispatch, false);
147
+ caseUpdateError.showFieldError(e, t('Severity'), () => applySeverityUpdate(payLoad));
136
148
  }
137
149
  });
138
150
  const onSeverityChange = (payLoad) => __awaiter(this, void 0, void 0, function* () {
@@ -145,16 +157,7 @@ export default function CaseOverview(props) {
145
157
  severity: payLoad.severity,
146
158
  }),
147
159
  });
148
- setSeverityUpdating(caseOverviewDispatch, true);
149
- try {
150
- yield updateOverviewCaseDetails(payLoad);
151
- setSeverityUpdating(caseOverviewDispatch, false);
152
- ToastNotification.addSuccessMessage(t('Severity has been successfully updated'));
153
- }
154
- catch (e) {
155
- setSeverityUpdating(caseOverviewDispatch, false);
156
- caseUpdateError.showError(e, t('Severity failed to update'));
157
- }
160
+ yield applySeverityUpdate(payLoad);
158
161
  });
159
162
  const showStatusUpdateSuccessToast = () => {
160
163
  ToastNotification.addSuccessMessage(t('Status has been successfully updated'));
@@ -179,7 +182,7 @@ export default function CaseOverview(props) {
179
182
  }
180
183
  catch (e) {
181
184
  setStatusUpdating(caseOverviewDispatch, false);
182
- caseUpdateError.showError(e, t('Status failed to update, try refreshing the page. Please contact us if the problem persists.'));
185
+ caseUpdateError.showFieldError(e, t('Status'), () => updateStatusState(statusVal, reopenedAt, reopenedBySSOName, reopenedReason, reopenedReasonOther, onStatusUpdate, options));
183
186
  return false;
184
187
  }
185
188
  });
@@ -316,7 +319,7 @@ export default function CaseOverview(props) {
316
319
  React.createElement("div", { className: "case-overview-secondary card card-md card-light push-bottom" },
317
320
  React.createElement("div", { className: "pf-v6-l-grid pf-m-gutter pf-m-all-4-col-on-lg" },
318
321
  React.createElement("div", { className: "form-wrapper" },
319
- React.createElement(CaseStatus, { selectedStatus: status, onStatusChange: onStatusChange, isDisabled: !canManageCase || allCaseStatuses.isFetching || canEditCase.isCaseNotEditable, isFetching: caseOverviewState.caseStatusUpdating && isCaseUpdating, hasError: allCaseStatuses.isError })),
322
+ React.createElement(CaseStatus, { selectedStatus: status, onStatusChange: onStatusChange, isDisabled: !canManageCase || allCaseStatuses.isFetching || canEditCase.isCaseNotEditable, isFetching: caseOverviewState.caseStatusUpdating && isCaseUpdating, hasError: allCaseStatuses.isError, isClosed: isCaseClosed, isInternal: loggedInUserRights.data.isInternal() })),
320
323
  React.createElement("div", { className: "form-wrapper" },
321
324
  React.createElement(CaseType, { selectedType: switchedCaseType, onTypeChange: onTypeChange, isDisabled: !canManageCase ||
322
325
  allCaseTypes.isFetching ||
@@ -330,22 +333,23 @@ export default function CaseOverview(props) {
330
333
  const success = yield updateStatusState(CaseStatusEnum.CLOSED, undefined, undefined, undefined, undefined, null, { showSuccessToast: false });
331
334
  if (success) {
332
335
  setShowCaseCloseModal(false);
333
- yield postCommentAfterStatusUpdate(commentBody);
334
- dtmTrackEventCaseStepEncountered('close', caseNumber, product, version);
335
336
  showStatusUpdateSuccessToast();
337
+ void postCommentAfterStatusUpdate(commentBody).then(() => {
338
+ dtmTrackEventCaseStepEncountered('close', caseNumber, product, version);
339
+ });
336
340
  }
337
341
  }), isUpdating: (caseOverviewState.caseStatusUpdating && isCaseUpdating) || isPostingComment, onClose: () => {
338
342
  setShowCaseCloseModal(false);
339
343
  }, caseNumber: caseNumber })),
340
344
  showReOpenCaseModal && (React.createElement(ReopenCaseModal, { isInternal: loggedInUserRights.data.isInternal(), onConfirm: (commentBody, newPortalStatus, reopenedAt, reopenedBySSOName, reopenedReason, reopenedReasonOther) => __awaiter(this, void 0, void 0, function* () {
341
345
  const newApiStatus = resolvePortalStatusToApiValue(newPortalStatus, status);
342
- const success = yield updateStatusState(newApiStatus, reopenedAt || null, reopenedBySSOName || null, reopenedReason || null, reopenedReasonOther || null, () => __awaiter(this, void 0, void 0, function* () {
343
- yield postCommentAfterStatusUpdate(commentBody);
344
- dtmTrackEventCaseStepEncountered('reopen', caseNumber, product, version);
345
- }), { showSuccessToast: false });
346
+ const success = yield updateStatusState(newApiStatus, reopenedAt || null, reopenedBySSOName || null, reopenedReason || null, reopenedReasonOther || null, null, { showSuccessToast: false });
346
347
  if (success) {
347
348
  setShowReopenCaseModal(false);
348
349
  showStatusUpdateSuccessToast();
350
+ void postCommentAfterStatusUpdate(commentBody).then(() => {
351
+ dtmTrackEventCaseStepEncountered('reopen', caseNumber, product, version);
352
+ });
349
353
  }
350
354
  }), onClose: () => {
351
355
  setShowReopenCaseModal(false);
@@ -1 +1 @@
1
- {"version":3,"file":"CaseSolutions.d.ts","sourceRoot":"","sources":["../../../../../src/components/CaseEditView/CaseSolutions/CaseSolutions.tsx"],"names":[],"mappings":"AA0BA,OAAO,KAAsD,MAAM,OAAO,CAAC;AAwF3E,UAAU,MAAM;IACZ,UAAU,EAAE,MAAM,CAAC;IACnB,sBAAsB,EAAE,OAAO,CAAC;CACnC;AAUD,eAAO,MAAM,aAAa,+EAshBxB,CAAC"}
1
+ {"version":3,"file":"CaseSolutions.d.ts","sourceRoot":"","sources":["../../../../../src/components/CaseEditView/CaseSolutions/CaseSolutions.tsx"],"names":[],"mappings":"AA0BA,OAAO,KAAsD,MAAM,OAAO,CAAC;AAwF3E,UAAU,MAAM;IACZ,UAAU,EAAE,MAAM,CAAC;IACnB,sBAAsB,EAAE,OAAO,CAAC;CACnC;AAUD,eAAO,MAAM,aAAa,+EAmhBxB,CAAC"}
@@ -161,7 +161,7 @@ export const CaseSolutions = forwardRef((props, ref) => {
161
161
  ToastNotification.addSuccessMessage(t('Status has been successfully updated'));
162
162
  }
163
163
  catch (err) {
164
- caseUpdateError.showError(err, t('Status failed to update, try refreshing the page. Please contact us if the problem persists.'));
164
+ caseUpdateError.showFieldError(err, t('Status'), handleCaseClose);
165
165
  }
166
166
  finally {
167
167
  setIsCaseCloseLoading(false);
@@ -9,7 +9,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
9
9
  };
10
10
  import { Button, ButtonVariant, Form, FormGroup, FormHelperText, HelperText, HelperTextItem, Modal, ModalBody, ModalFooter, ModalHeader, ModalVariant, TextArea, } from '@patternfly/react-core';
11
11
  import { SingleSelectDropdown } from '@rh-support/components';
12
- import { formatDateTime, PORTAL_OPEN_DISPLAY_STATUSES } from '@rh-support/utils';
12
+ import { formatDateTime, PORTAL_REOPEN_STATUSES } from '@rh-support/utils';
13
13
  import isEmpty from 'lodash/isEmpty';
14
14
  import map from 'lodash/map';
15
15
  import React, { useState } from 'react';
@@ -66,7 +66,7 @@ export function ReopenCaseModal(props) {
66
66
  label: option,
67
67
  value: option,
68
68
  }));
69
- const getStatusDropdownOptions = map(PORTAL_OPEN_DISPLAY_STATUSES, (option) => ({
69
+ const getStatusDropdownOptions = map(PORTAL_REOPEN_STATUSES, (option) => ({
70
70
  label: option,
71
71
  value: option,
72
72
  }));
@@ -1 +1 @@
1
- {"version":3,"file":"NewEssTermsModal.d.ts","sourceRoot":"","sources":["../../../../../src/components/CaseEditView/RequestRemoteSession/NewEssTermsModal.tsx"],"names":[],"mappings":"AAsBA,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAC/D,OAAO,EAAE,QAAQ,EAAE,MAAM,8BAA8B,CAAC;AAExD,OAAO,KAA8B,MAAM,OAAO,CAAC;AAYnD,UAAU,MAAM;IACZ,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,OAAO,CAAC;IACd,kBAAkB,EAAE,mBAAmB,CAAC,QAAQ,CAAC,CAAC;IAClD,QAAQ,EAAE,OAAO,CAAC;CACrB;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,qBAwb7C"}
1
+ {"version":3,"file":"NewEssTermsModal.d.ts","sourceRoot":"","sources":["../../../../../src/components/CaseEditView/RequestRemoteSession/NewEssTermsModal.tsx"],"names":[],"mappings":"AAsBA,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAC/D,OAAO,EAAE,QAAQ,EAAE,MAAM,8BAA8B,CAAC;AAGxD,OAAO,KAA8B,MAAM,OAAO,CAAC;AAanD,UAAU,MAAM;IACZ,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,OAAO,CAAC;IACd,kBAAkB,EAAE,mBAAmB,CAAC,QAAQ,CAAC,CAAC;IAClD,QAAQ,EAAE,OAAO,CAAC;CACrB;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,qBA0b7C"}
@@ -13,13 +13,14 @@ import { Alert, Button, ButtonVariant, Checkbox, Modal, ModalBody, ModalFooter,
13
13
  import DownloadIcon from '@patternfly/react-icons/dist/js/icons/download-icon';
14
14
  import ExternalLinkAltIcon from '@patternfly/react-icons/dist/js/icons/external-link-alt-icon';
15
15
  import { SingleSelectDropdown, useFetch } from '@rh-support/components';
16
+ import { resolveSalesforceUserIdByFederationId } from '@rh-support/utils';
16
17
  import isEqual from 'lodash/isEqual';
17
18
  import React, { useEffect, useState } from 'react';
18
19
  import { Trans, useTranslation } from 'react-i18next';
19
20
  import { useCaseDispatch, useCaseSelector } from '../../../context/CaseContext';
20
21
  import { GET_CASE_COMMENTS, useCreateCaseComment } from '../../../hooks/useCaseComments';
21
22
  import { checkForCaseStatusToggleOnAttachOrComment, updateCaseDetailsGraphQL } from '../../../reducers/CaseReducer';
22
- import { formatSessionLinks, getLocaleNameFromLocalCode, REMOTE_SESSION_FIELD_LENGTH_LIMIT, } from './remoteSessionUtils';
23
+ import { buildRemoteSessionRequestCaseUpdate, formatSessionLinks, getLocaleNameFromLocalCode, REMOTE_SESSION_FIELD_LENGTH_LIMIT, } from './remoteSessionUtils';
23
24
  export function NewEssTermsModal(props) {
24
25
  const { t } = useTranslation();
25
26
  const { remoteSessionTermsAcked } = useCaseSelector((state) => ({
@@ -127,10 +128,11 @@ export function NewEssTermsModal(props) {
127
128
  ? `<p><strong>Remote session link</strong></p><p>${formatSessionLinks(sessionLink)}</p>`
128
129
  : ''}<p>This action does not initiate a remote session. A Red Hat Associate will get back to you soon.</p>`);
129
130
  try {
130
- yield updateCaseDetailsGraphQL(caseDispatch, apolloClient, props.caseNumber, {
131
- remoteSessionTermsAcked: true,
132
- waitingOnCallback: true,
133
- }, false, { existingCaseDetails });
131
+ const ackedByUserId = yield resolveSalesforceUserIdByFederationId(apolloClient, props.loggedInUser);
132
+ if (!ackedByUserId) {
133
+ throw new Error('Salesforce user id is required to request a remote session');
134
+ }
135
+ yield updateCaseDetailsGraphQL(caseDispatch, apolloClient, props.caseNumber, buildRemoteSessionRequestCaseUpdate(ackedByUserId), false, { existingCaseDetails });
134
136
  try {
135
137
  yield createComment({
136
138
  caseId: caseSalesforceId,
@@ -1 +1 @@
1
- {"version":3,"file":"RemoteSessionAgreementModal.d.ts","sourceRoot":"","sources":["../../../../../src/components/CaseEditView/RequestRemoteSession/RemoteSessionAgreementModal.tsx"],"names":[],"mappings":"AAsBA,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAC/D,OAAO,EAAE,QAAQ,EAAE,MAAM,8BAA8B,CAAC;AAExD,OAAO,KAA8B,MAAM,OAAO,CAAC;AAgBnD,UAAU,MAAM;IACZ,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,OAAO,CAAC;IACd,kBAAkB,EAAE,mBAAmB,CAAC,QAAQ,CAAC,CAAC;IAClD,QAAQ,EAAE,OAAO,CAAC;CACrB;AAED,wBAAgB,2BAA2B,CAAC,KAAK,EAAE,MAAM,qBAibxD"}
1
+ {"version":3,"file":"RemoteSessionAgreementModal.d.ts","sourceRoot":"","sources":["../../../../../src/components/CaseEditView/RequestRemoteSession/RemoteSessionAgreementModal.tsx"],"names":[],"mappings":"AAsBA,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAC/D,OAAO,EAAE,QAAQ,EAAE,MAAM,8BAA8B,CAAC;AAGxD,OAAO,KAA8B,MAAM,OAAO,CAAC;AAiBnD,UAAU,MAAM;IACZ,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,OAAO,CAAC;IACd,kBAAkB,EAAE,mBAAmB,CAAC,QAAQ,CAAC,CAAC;IAClD,QAAQ,EAAE,OAAO,CAAC;CACrB;AAED,wBAAgB,2BAA2B,CAAC,KAAK,EAAE,MAAM,qBAmbxD"}
@@ -13,13 +13,14 @@ import { Alert, Button, ButtonVariant, Checkbox, Modal, ModalBody, ModalFooter,
13
13
  import DownloadIcon from '@patternfly/react-icons/dist/js/icons/download-icon';
14
14
  import ExternalLinkAltIcon from '@patternfly/react-icons/dist/js/icons/external-link-alt-icon';
15
15
  import { SingleSelectDropdown, useFetch } from '@rh-support/components';
16
+ import { resolveSalesforceUserIdByFederationId } from '@rh-support/utils';
16
17
  import isEqual from 'lodash/isEqual';
17
18
  import React, { useEffect, useState } from 'react';
18
19
  import { Trans, useTranslation } from 'react-i18next';
19
20
  import { useCaseDispatch, useCaseSelector } from '../../../context/CaseContext';
20
21
  import { GET_CASE_COMMENTS, useCreateCaseComment } from '../../../hooks/useCaseComments';
21
22
  import { checkForCaseStatusToggleOnAttachOrComment, setRemoteRiderFlag, updateCaseDetailsGraphQL, } from '../../../reducers/CaseReducer';
22
- import { formatSessionLinks, getLocaleNameFromLocalCode, REMOTE_SESSION_FIELD_LENGTH_LIMIT, } from './remoteSessionUtils';
23
+ import { buildRemoteSessionRequestCaseUpdate, formatSessionLinks, getLocaleNameFromLocalCode, REMOTE_SESSION_FIELD_LENGTH_LIMIT, } from './remoteSessionUtils';
23
24
  export function RemoteSessionAgreementModal(props) {
24
25
  const { t } = useTranslation();
25
26
  const { remoteSessionTermsAcked } = useCaseSelector((state) => ({
@@ -118,10 +119,11 @@ export function RemoteSessionAgreementModal(props) {
118
119
  ? `<p><strong>Remote session link</strong></p><p>${formatSessionLinks(sessionLink)}</p>`
119
120
  : ''}<p>This action does not initiate a remote session. A Red Hat Associate will get back to you soon.</p>`);
120
121
  try {
121
- yield updateCaseDetailsGraphQL(caseDispatch, apolloClient, props.caseNumber, {
122
- remoteSessionTermsAcked: true,
123
- waitingOnCallback: true,
124
- }, false, { existingCaseDetails });
122
+ const ackedByUserId = yield resolveSalesforceUserIdByFederationId(apolloClient, props.loggedInUser);
123
+ if (!ackedByUserId) {
124
+ throw new Error('Salesforce user id is required to request a remote session');
125
+ }
126
+ yield updateCaseDetailsGraphQL(caseDispatch, apolloClient, props.caseNumber, buildRemoteSessionRequestCaseUpdate(ackedByUserId), false, { existingCaseDetails });
125
127
  setRemoteRiderFlag(caseDispatch, true);
126
128
  try {
127
129
  yield createComment({
@@ -1,4 +1,10 @@
1
1
  export declare const REMOTE_SESSION_FIELD_LENGTH_LIMIT = 2000;
2
+ export declare function buildRemoteSessionRequestCaseUpdate(ackedByUserId: string): {
3
+ remoteSessionTermsAcked: boolean;
4
+ waitingOnCallback: boolean;
5
+ remoteSessionTermsAckedBy: string;
6
+ remoteSessionTermsAckedDate: string;
7
+ };
2
8
  export declare const getLocaleNameFromLocalCode: (localeCode: string) => string;
3
9
  export declare const formatSessionLinks: (sessionLink: string) => string;
4
10
  //# sourceMappingURL=remoteSessionUtils.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"remoteSessionUtils.d.ts","sourceRoot":"","sources":["../../../../../src/components/CaseEditView/RequestRemoteSession/remoteSessionUtils.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,iCAAiC,OAAO,CAAC;AAEtD,eAAO,MAAM,0BAA0B,GAAI,YAAY,MAAM,KAAG,MAa/D,CAAC;AAEF,eAAO,MAAM,kBAAkB,GAAI,aAAa,MAAM,KAAG,MAOxD,CAAC"}
1
+ {"version":3,"file":"remoteSessionUtils.d.ts","sourceRoot":"","sources":["../../../../../src/components/CaseEditView/RequestRemoteSession/remoteSessionUtils.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,iCAAiC,OAAO,CAAC;AAEtD,wBAAgB,mCAAmC,CAAC,aAAa,EAAE,MAAM;;;;;EAOxE;AAED,eAAO,MAAM,0BAA0B,GAAI,YAAY,MAAM,KAAG,MAa/D,CAAC;AAEF,eAAO,MAAM,kBAAkB,GAAI,aAAa,MAAM,KAAG,MAOxD,CAAC"}
@@ -1,4 +1,12 @@
1
1
  export const REMOTE_SESSION_FIELD_LENGTH_LIMIT = 2000;
2
+ export function buildRemoteSessionRequestCaseUpdate(ackedByUserId) {
3
+ return {
4
+ remoteSessionTermsAcked: true,
5
+ waitingOnCallback: true,
6
+ remoteSessionTermsAckedBy: ackedByUserId,
7
+ remoteSessionTermsAckedDate: new Date().toISOString(),
8
+ };
9
+ }
2
10
  export const getLocaleNameFromLocalCode = (localeCode) => {
3
11
  if ('Intl' in window && 'DisplayNames' in Intl) {
4
12
  try {
@@ -1 +1 @@
1
- {"version":3,"file":"CaseActionPlan.d.ts","sourceRoot":"","sources":["../../../../../../src/components/CaseEditView/Tabs/CaseActionPlan/CaseActionPlan.tsx"],"names":[],"mappings":"AAYA,OAAO,KAA0C,MAAM,OAAO,CAAC;AAQ/D,UAAU,MAAM;IACZ,UAAU,EAAE,MAAM,CAAC;CACtB;AAMD,iBAAS,cAAc,CAAC,KAAK,EAAE,MAAM,qBA4HpC;kBA5HQ,cAAc;;;AA+HvB,eAAe,cAAc,CAAC"}
1
+ {"version":3,"file":"CaseActionPlan.d.ts","sourceRoot":"","sources":["../../../../../../src/components/CaseEditView/Tabs/CaseActionPlan/CaseActionPlan.tsx"],"names":[],"mappings":"AAYA,OAAO,KAA0C,MAAM,OAAO,CAAC;AAQ/D,UAAU,MAAM;IACZ,UAAU,EAAE,MAAM,CAAC;CACtB;AAMD,iBAAS,cAAc,CAAC,KAAK,EAAE,MAAM,qBAgIpC;kBAhIQ,cAAc;;;AAmIvB,eAAe,cAAc,CAAC"}
@@ -39,8 +39,7 @@ function CaseActionPlan(props) {
39
39
  }
40
40
  // eslint-disable-next-line react-hooks/exhaustive-deps
41
41
  }, [actionPlan]);
42
- const updateCase = (event) => __awaiter(this, void 0, void 0, function* () {
43
- event.preventDefault();
42
+ const persistActionPlan = () => __awaiter(this, void 0, void 0, function* () {
44
43
  setIsUpdating(true);
45
44
  try {
46
45
  const caseDetails = { actionPlan: actionPlanState };
@@ -50,10 +49,14 @@ function CaseActionPlan(props) {
50
49
  setIsUpdating(false);
51
50
  }
52
51
  catch (e) {
53
- caseUpdateError.showError(e, t('Action plan failed to update'));
52
+ caseUpdateError.showFieldError(e, t('Action plan'), persistActionPlan);
54
53
  setIsUpdating(false);
55
54
  }
56
55
  });
56
+ const updateCase = (event) => __awaiter(this, void 0, void 0, function* () {
57
+ event.preventDefault();
58
+ yield persistActionPlan();
59
+ });
57
60
  const discardActionPlan = (event) => {
58
61
  event.preventDefault();
59
62
  setActionPlan(actionPlan);
@@ -128,7 +128,7 @@ export function CaseContactPhoneNumber() {
128
128
  catch (e) {
129
129
  setCaseState(caseDispatch, { isCasePhoneUpdating: false });
130
130
  setIsEditting(false);
131
- caseUpdateError.showError(e, t(`Phone number failed to update`));
131
+ caseUpdateError.showFieldError(e, t('Phone number'), onSave);
132
132
  }
133
133
  });
134
134
  const onClear = () => __awaiter(this, void 0, void 0, function* () {
@@ -1 +1 @@
1
- {"version":3,"file":"CaseDetailsManagement.d.ts","sourceRoot":"","sources":["../../../../../../src/components/CaseEditView/Tabs/CaseDetails/CaseDetailsManagement.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAG5D,OAAO,KAA+B,MAAM,OAAO,CAAC;AAEpD,OAAO,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAqBvD,UAAU,MAAO,SAAQ,gBAAgB;IACrC,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,mBAAmB,CAAC;IAChC,MAAM,EAAE,KAAK,CAAC,gBAAgB,CAAC,cAAc,CAAC,CAAC;CAClD;AAED,MAAM,CAAC,OAAO,UAAU,qBAAqB,CAAC,KAAK,EAAE,MAAM,qBAwF1D"}
1
+ {"version":3,"file":"CaseDetailsManagement.d.ts","sourceRoot":"","sources":["../../../../../../src/components/CaseEditView/Tabs/CaseDetails/CaseDetailsManagement.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAI5D,OAAO,KAA0C,MAAM,OAAO,CAAC;AAE/D,OAAO,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAsBvD,UAAU,MAAO,SAAQ,gBAAgB;IACrC,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,mBAAmB,CAAC;IAChC,MAAM,EAAE,KAAK,CAAC,gBAAgB,CAAC,cAAc,CAAC,CAAC;CAClD;AAED,MAAM,CAAC,OAAO,UAAU,qBAAqB,CAAC,KAAK,EAAE,MAAM,qBAgI1D"}
@@ -1,11 +1,14 @@
1
+ import { useApolloClient } from '@apollo/client/react';
1
2
  import { Flex, FlexItem } from '@patternfly/react-core';
2
3
  import { AlertMessage, AlertType } from '@rh-support/components';
3
4
  import { AbilityContext, CaseDetailsFields, resourceActions, resources } from '@rh-support/user-permissions';
5
+ import isEmpty from 'lodash/isEmpty';
4
6
  import isEqual from 'lodash/isEqual';
5
- import React, { useContext, useState } from 'react';
7
+ import React, { useContext, useEffect, useState } from 'react';
6
8
  import { useTranslation } from 'react-i18next';
7
- import { useCaseSelector } from '../../../../context/CaseContext';
9
+ import { useCaseDispatch, useCaseSelector } from '../../../../context/CaseContext';
8
10
  import { useShowCaseGroupField } from '../../../../hooks/useCaseGroupUiState';
11
+ import { fetchCaseGroupsForContactGraphQL } from '../../../../reducers/CaseReducer';
9
12
  import { OwnerSelector } from '../../../AccountInfo/OwnerSelector';
10
13
  import CaseGroup from '../../../CaseInformation/CaseGroup';
11
14
  import CaseLabels from '../../../CaseInformation/CaseLabels';
@@ -25,15 +28,45 @@ import SFDCUrl from './SFDCUrl';
25
28
  export default function CaseDetailsManagement(props) {
26
29
  const { t } = useTranslation();
27
30
  const [isUpdatingPartner, setIsUpdatingPartner] = useState(false);
28
- const caseState = useCaseSelector((state) => ({
29
- caseDetails: {
30
- accountNumber: state.caseDetails.accountNumberRef,
31
- },
32
- showMandatoryCaseGroupValidationError: state.showMandatoryCaseGroupValidationError,
33
- }), isEqual);
31
+ const caseDispatch = useCaseDispatch();
32
+ const apolloClient = useApolloClient();
33
+ const caseState = useCaseSelector((state) => {
34
+ var _a, _b, _c, _d, _e;
35
+ return ({
36
+ caseDetails: {
37
+ accountNumber: state.caseDetails.accountNumberRef,
38
+ groupNumber: state.caseDetails.groupNumber,
39
+ },
40
+ showMandatoryCaseGroupValidationError: state.showMandatoryCaseGroupValidationError,
41
+ selectedOwnerContactId: (_b = (_a = state.selectedOwner) === null || _a === void 0 ? void 0 : _a.data) === null || _b === void 0 ? void 0 : _b.id,
42
+ selectedOwnerIsOrgAdmin: (_e = (_d = (_c = state.selectedOwner) === null || _c === void 0 ? void 0 : _c.data) === null || _d === void 0 ? void 0 : _d.isOrgAdmin) !== null && _e !== void 0 ? _e : false,
43
+ ownersCaseGroupsData: state.ownersCaseGroups.data,
44
+ ownersCaseGroupsFetching: state.ownersCaseGroups.isFetching,
45
+ });
46
+ }, isEqual);
34
47
  const accountNumber = caseState.caseDetails.accountNumber;
48
+ const groupNumber = caseState.caseDetails.groupNumber;
35
49
  const showCaseGroupField = useShowCaseGroupField();
36
50
  const ability = useContext(AbilityContext);
51
+ useEffect(() => {
52
+ const { selectedOwnerContactId, ownersCaseGroupsData, ownersCaseGroupsFetching } = caseState;
53
+ if (!props.caseNumber || isEmpty(accountNumber) || isEmpty(selectedOwnerContactId)) {
54
+ return;
55
+ }
56
+ if (ownersCaseGroupsFetching || ownersCaseGroupsData !== undefined) {
57
+ return;
58
+ }
59
+ fetchCaseGroupsForContactGraphQL(caseDispatch, apolloClient, selectedOwnerContactId, accountNumber, groupNumber || null, caseState.selectedOwnerIsOrgAdmin, groupNumber !== null && groupNumber !== void 0 ? groupNumber : '');
60
+ // eslint-disable-next-line react-hooks/exhaustive-deps
61
+ }, [
62
+ props.caseNumber,
63
+ accountNumber,
64
+ caseState.selectedOwnerContactId,
65
+ caseState.selectedOwnerIsOrgAdmin,
66
+ groupNumber,
67
+ caseState.ownersCaseGroupsData,
68
+ caseState.ownersCaseGroupsFetching,
69
+ ]);
37
70
  // const canSeeEmailNotifications = ability.can(
38
71
  // resourceActions.PATCH,
39
72
  // resources.CASE_DETAILS,
@@ -64,7 +64,7 @@ function CaseHostname(props) {
64
64
  }
65
65
  catch (e) {
66
66
  setIsHostnameUpdating(false);
67
- caseUpdateError.showError(e, t('Hostname failed to updated'));
67
+ caseUpdateError.showFieldError(e, t('Hostname'), () => onHostnameUpdate(caseDetails));
68
68
  throw e;
69
69
  }
70
70
  });
@@ -53,7 +53,7 @@ export default function CaseInternalStatus() {
53
53
  }
54
54
  catch (e) {
55
55
  setIsIStatusUpdating(false);
56
- caseUpdateError.showError(e, t('Case Internal Status failed to update'));
56
+ caseUpdateError.showFieldError(e, t('Internal status'), () => onCaseInternalStatusChange(event, selection));
57
57
  }
58
58
  });
59
59
  useEffect(() => {