resolutionBox.tsx 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. import {Fragment} from 'react';
  2. import styled from '@emotion/styled';
  3. import UserAvatar from 'sentry/components/avatar/userAvatar';
  4. import CommitLink from 'sentry/components/commitLink';
  5. import {BannerContainer, BannerSummary} from 'sentry/components/events/styles';
  6. import TimeSince from 'sentry/components/timeSince';
  7. import Version from 'sentry/components/version';
  8. import {IconCheckmark} from 'sentry/icons';
  9. import {t, tct} from 'sentry/locale';
  10. import space from 'sentry/styles/space';
  11. import {
  12. GroupActivity,
  13. GroupActivitySetByResolvedInRelease,
  14. GroupActivityType,
  15. ResolutionStatusDetails,
  16. } from 'sentry/types';
  17. type Props = {
  18. projectId: string;
  19. statusDetails: ResolutionStatusDetails;
  20. activities?: GroupActivity[];
  21. };
  22. function renderReason(
  23. statusDetails: ResolutionStatusDetails,
  24. projectId: string,
  25. activities: GroupActivity[]
  26. ) {
  27. const actor = statusDetails.actor ? (
  28. <strong>
  29. <UserAvatar user={statusDetails.actor} size={20} className="avatar" />
  30. <span style={{marginLeft: 5}}>{statusDetails.actor.name}</span>
  31. </strong>
  32. ) : null;
  33. const relevantActivity = activities.find(
  34. activity => activity.type === GroupActivityType.SET_RESOLVED_IN_RELEASE
  35. ) as GroupActivitySetByResolvedInRelease | undefined;
  36. const currentReleaseVersion = relevantActivity?.data.current_release_version!;
  37. if (statusDetails.inNextRelease && statusDetails.actor) {
  38. return tct('[actor] marked this issue as resolved in the upcoming release.', {
  39. actor,
  40. });
  41. }
  42. if (statusDetails.inNextRelease) {
  43. return t('This issue has been marked as resolved in the upcoming release.');
  44. }
  45. if (statusDetails.inRelease && statusDetails.actor) {
  46. return currentReleaseVersion
  47. ? tct('[actor] marked this issue as resolved in versions greater than [version].', {
  48. actor,
  49. version: (
  50. <Version
  51. version={currentReleaseVersion}
  52. projectId={projectId}
  53. tooltipRawVersion
  54. />
  55. ),
  56. })
  57. : tct('[actor] marked this issue as resolved in version [version].', {
  58. actor,
  59. version: (
  60. <Version
  61. version={statusDetails.inRelease}
  62. projectId={projectId}
  63. tooltipRawVersion
  64. />
  65. ),
  66. });
  67. }
  68. if (statusDetails.inRelease) {
  69. return currentReleaseVersion
  70. ? tct(
  71. 'This issue has been marked as resolved in versions greater than [version].',
  72. {
  73. version: (
  74. <Version
  75. version={currentReleaseVersion}
  76. projectId={projectId}
  77. tooltipRawVersion
  78. />
  79. ),
  80. }
  81. )
  82. : tct('This issue has been marked as resolved in version [version].', {
  83. version: (
  84. <Version
  85. version={statusDetails.inRelease}
  86. projectId={projectId}
  87. tooltipRawVersion
  88. />
  89. ),
  90. });
  91. }
  92. if (!!statusDetails.inCommit) {
  93. return tct('This issue has been marked as resolved by [commit]', {
  94. commit: (
  95. <Fragment>
  96. <CommitLink
  97. commitId={statusDetails.inCommit.id}
  98. repository={statusDetails.inCommit.repository}
  99. />
  100. <StyledTimeSince date={statusDetails.inCommit.dateCreated} />
  101. </Fragment>
  102. ),
  103. });
  104. }
  105. return t('This issue has been marked as resolved.');
  106. }
  107. function ResolutionBox({statusDetails, projectId, activities = []}: Props) {
  108. return (
  109. <BannerContainer priority="default">
  110. <BannerSummary>
  111. <StyledIconCheckmark color="green300" />
  112. <span>{renderReason(statusDetails, projectId, activities)}</span>
  113. </BannerSummary>
  114. </BannerContainer>
  115. );
  116. }
  117. const StyledTimeSince = styled(TimeSince)`
  118. color: ${p => p.theme.gray300};
  119. margin-left: ${space(0.5)};
  120. font-size: ${p => p.theme.fontSizeSmall};
  121. `;
  122. const StyledIconCheckmark = styled(IconCheckmark)`
  123. /* override margin defined in BannerSummary */
  124. margin-top: 0 !important;
  125. align-self: center;
  126. @media (max-width: ${p => p.theme.breakpoints.small}) {
  127. margin-top: ${space(0.5)} !important;
  128. align-self: flex-start;
  129. }
  130. `;
  131. export default ResolutionBox;