seenInfo.tsx 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. import * as React from 'react';
  2. import {css} from '@emotion/react';
  3. import styled from '@emotion/styled';
  4. import DateTime from 'app/components/dateTime';
  5. import {Body, Header, Hovercard} from 'app/components/hovercard';
  6. import TimeSince from 'app/components/timeSince';
  7. import Version from 'app/components/version';
  8. import VersionHoverCard from 'app/components/versionHoverCard';
  9. import {t} from 'app/locale';
  10. import overflowEllipsis from 'app/styles/overflowEllipsis';
  11. import space from 'app/styles/space';
  12. import {Organization, Release} from 'app/types';
  13. import {defined, toTitleCase} from 'app/utils';
  14. import theme from 'app/utils/theme';
  15. type RelaxedDateType = React.ComponentProps<typeof TimeSince>['date'];
  16. type Props = {
  17. organization: Organization;
  18. projectSlug: string;
  19. projectId: string;
  20. hasRelease: boolean;
  21. title: string;
  22. date: RelaxedDateType;
  23. dateGlobal: RelaxedDateType;
  24. release?: Release;
  25. environment?: string;
  26. };
  27. class SeenInfo extends React.Component<Props> {
  28. shouldComponentUpdate(nextProps: Props) {
  29. const {date, release} = this.props;
  30. return release?.version !== nextProps.release?.version || date !== nextProps.date;
  31. }
  32. getReleaseTrackingUrl() {
  33. const {organization, projectSlug} = this.props;
  34. const orgSlug = organization.slug;
  35. return `/settings/${orgSlug}/projects/${projectSlug}/release-tracking/`;
  36. }
  37. render() {
  38. const {date, dateGlobal, environment, release, organization, projectSlug, projectId} =
  39. this.props;
  40. return (
  41. <HovercardWrapper>
  42. <StyledHovercard
  43. header={
  44. <div>
  45. <TimeSinceWrapper>
  46. {t('Any Environment')}
  47. <TimeSince date={dateGlobal} disabledAbsoluteTooltip />
  48. </TimeSinceWrapper>
  49. {environment && (
  50. <TimeSinceWrapper>
  51. {toTitleCase(environment)}
  52. {date ? (
  53. <TimeSince date={date} disabledAbsoluteTooltip />
  54. ) : (
  55. <span>{t('N/A')}</span>
  56. )}
  57. </TimeSinceWrapper>
  58. )}
  59. </div>
  60. }
  61. body={
  62. date ? (
  63. <StyledDateTime date={date} />
  64. ) : (
  65. <NoEnvironment>{t(`N/A for ${environment}`)}</NoEnvironment>
  66. )
  67. }
  68. position="top"
  69. tipColor={theme.gray500}
  70. >
  71. <DateWrapper>
  72. {date ? (
  73. <TooltipWrapper>
  74. <StyledTimeSince date={date} disabledAbsoluteTooltip />
  75. </TooltipWrapper>
  76. ) : dateGlobal && environment === '' ? (
  77. <React.Fragment>
  78. <TimeSince date={dateGlobal} disabledAbsoluteTooltip />
  79. <StyledTimeSince date={dateGlobal} disabledAbsoluteTooltip />
  80. </React.Fragment>
  81. ) : (
  82. <NoDateTime>{t('N/A')}</NoDateTime>
  83. )}
  84. </DateWrapper>
  85. </StyledHovercard>
  86. <DateWrapper>
  87. {defined(release) ? (
  88. <React.Fragment>
  89. {t('in release ')}
  90. <VersionHoverCard
  91. organization={organization}
  92. projectSlug={projectSlug}
  93. releaseVersion={release.version}
  94. >
  95. <span>
  96. <Version version={release.version} projectId={projectId} />
  97. </span>
  98. </VersionHoverCard>
  99. </React.Fragment>
  100. ) : null}
  101. </DateWrapper>
  102. </HovercardWrapper>
  103. );
  104. }
  105. }
  106. const dateTimeCss = p => css`
  107. color: ${p.theme.gray300};
  108. font-size: ${p.theme.fontSizeMedium};
  109. display: flex;
  110. justify-content: center;
  111. `;
  112. const HovercardWrapper = styled('div')`
  113. display: flex;
  114. `;
  115. const DateWrapper = styled('div')`
  116. margin-bottom: ${space(2)};
  117. ${overflowEllipsis};
  118. `;
  119. const StyledDateTime = styled(DateTime)`
  120. ${dateTimeCss};
  121. `;
  122. const NoEnvironment = styled('div')`
  123. ${dateTimeCss};
  124. `;
  125. const NoDateTime = styled('span')`
  126. margin-right: ${space(0.5)};
  127. `;
  128. const TooltipWrapper = styled('span')`
  129. margin-right: ${space(0.25)};
  130. svg {
  131. margin-right: ${space(0.5)};
  132. position: relative;
  133. top: 1px;
  134. }
  135. `;
  136. const TimeSinceWrapper = styled('div')`
  137. font-size: ${p => p.theme.fontSizeSmall};
  138. margin-bottom: ${space(0.5)};
  139. display: flex;
  140. justify-content: space-between;
  141. `;
  142. const StyledTimeSince = styled(TimeSince)`
  143. font-size: ${p => p.theme.fontSizeMedium};
  144. `;
  145. const StyledHovercard = styled(Hovercard)`
  146. width: 250px;
  147. font-weight: normal;
  148. border: 1px solid ${p => p.theme.gray500};
  149. background: ${p => p.theme.gray500};
  150. ${Header} {
  151. font-weight: normal;
  152. color: ${p => p.theme.white};
  153. background: ${p => p.theme.gray500};
  154. border-bottom: 1px solid ${p => p.theme.gray400};
  155. }
  156. ${Body} {
  157. padding: ${space(1.5)};
  158. }
  159. `;
  160. export default SeenInfo;