releaseStats.tsx 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. import {Fragment, memo} from 'react';
  2. import styled from '@emotion/styled';
  3. import AlertLink from 'sentry/components/alertLink';
  4. import GroupReleaseChart from 'sentry/components/group/releaseChart';
  5. import SeenInfo from 'sentry/components/group/seenInfo';
  6. import Placeholder from 'sentry/components/placeholder';
  7. import * as SidebarSection from 'sentry/components/sidebarSection';
  8. import Tooltip from 'sentry/components/tooltip';
  9. import {IconQuestion} from 'sentry/icons';
  10. import {t} from 'sentry/locale';
  11. import space from 'sentry/styles/space';
  12. import {CurrentRelease, Environment, Group, Organization, Project} from 'sentry/types';
  13. import getDynamicText from 'sentry/utils/getDynamicText';
  14. type Props = {
  15. allEnvironments: Group | undefined;
  16. currentRelease: CurrentRelease | undefined;
  17. environments: Environment[];
  18. group: Group | undefined;
  19. organization: Organization;
  20. project: Project;
  21. };
  22. const GroupReleaseStats = ({
  23. organization,
  24. project,
  25. environments,
  26. allEnvironments,
  27. group,
  28. currentRelease,
  29. }: Props) => {
  30. const environment =
  31. environments.length > 0
  32. ? environments.map(env => env.displayName).join(', ')
  33. : undefined;
  34. const environmentLabel = environment ? environment : t('All Environments');
  35. const shortEnvironmentLabel =
  36. environments.length > 1
  37. ? t('selected environments')
  38. : environments.length === 1
  39. ? environments[0].displayName
  40. : undefined;
  41. const projectId = project.id;
  42. const projectSlug = project.slug;
  43. const hasRelease = new Set(project.features).has('releases');
  44. const releaseTrackingUrl = `/settings/${organization.slug}/projects/${project.slug}/release-tracking/`;
  45. return (
  46. <div>
  47. {!group || !allEnvironments ? (
  48. <Placeholder height="288px" />
  49. ) : (
  50. <Fragment>
  51. <GraphContainer>
  52. <GroupReleaseChart
  53. group={allEnvironments}
  54. environment={environment}
  55. environmentLabel={environmentLabel}
  56. environmentStats={group.stats}
  57. release={currentRelease?.release}
  58. releaseStats={currentRelease?.stats}
  59. statsPeriod="24h"
  60. title={t('Last 24 Hours')}
  61. firstSeen={group.firstSeen}
  62. lastSeen={group.lastSeen}
  63. />
  64. </GraphContainer>
  65. <GraphContainer>
  66. <GroupReleaseChart
  67. group={allEnvironments}
  68. environment={environment}
  69. environmentLabel={environmentLabel}
  70. environmentStats={group.stats}
  71. release={currentRelease?.release}
  72. releaseStats={currentRelease?.stats}
  73. statsPeriod="30d"
  74. title={t('Last 30 Days')}
  75. className="bar-chart-small"
  76. firstSeen={group.firstSeen}
  77. lastSeen={group.lastSeen}
  78. />
  79. </GraphContainer>
  80. <SidebarSection.Wrap>
  81. <SidebarSection.Title>
  82. <Fragment>
  83. {t('Last Seen')}
  84. <TooltipWrapper>
  85. <Tooltip
  86. title={t('When the most recent event in this issue was captured.')}
  87. disableForVisualTest
  88. >
  89. <IconQuestion size="sm" color="gray200" />
  90. </Tooltip>
  91. </TooltipWrapper>
  92. </Fragment>
  93. </SidebarSection.Title>
  94. <StyledSidebarSectionContent>
  95. <SeenInfo
  96. organization={organization}
  97. projectId={projectId}
  98. projectSlug={projectSlug}
  99. date={getDynamicText({
  100. value: group.lastSeen,
  101. fixed: '2016-01-13T03:08:25Z',
  102. })}
  103. dateGlobal={allEnvironments.lastSeen}
  104. hasRelease={hasRelease}
  105. environment={shortEnvironmentLabel}
  106. release={group.lastRelease || null}
  107. title={t('Last Seen')}
  108. />
  109. </StyledSidebarSectionContent>
  110. </SidebarSection.Wrap>
  111. <SidebarSection.Wrap>
  112. <SidebarSection.Title>
  113. <Fragment>
  114. {t('First Seen')}
  115. <TooltipWrapper>
  116. <Tooltip
  117. title={t('When the first event in this issue was captured.')}
  118. disableForVisualTest
  119. >
  120. <IconQuestion size="sm" color="gray200" />
  121. </Tooltip>
  122. </TooltipWrapper>
  123. </Fragment>
  124. </SidebarSection.Title>
  125. <StyledSidebarSectionContent>
  126. <SeenInfo
  127. organization={organization}
  128. projectId={projectId}
  129. projectSlug={projectSlug}
  130. date={getDynamicText({
  131. value: group.firstSeen,
  132. fixed: '2015-08-13T03:08:25Z',
  133. })}
  134. dateGlobal={allEnvironments.firstSeen}
  135. hasRelease={hasRelease}
  136. environment={shortEnvironmentLabel}
  137. release={group.firstRelease || null}
  138. title={t('First seen')}
  139. />
  140. </StyledSidebarSectionContent>
  141. </SidebarSection.Wrap>
  142. {!hasRelease ? (
  143. <SidebarSection.Wrap>
  144. <SidebarSection.Title>{t('Releases')}</SidebarSection.Title>
  145. <SidebarSection.Content>
  146. <AlertLink priority="muted" size="small" to={releaseTrackingUrl}>
  147. {t('See which release caused this issue ')}
  148. </AlertLink>
  149. </SidebarSection.Content>
  150. </SidebarSection.Wrap>
  151. ) : null}
  152. </Fragment>
  153. )}
  154. </div>
  155. );
  156. };
  157. export default memo(GroupReleaseStats);
  158. const TooltipWrapper = styled('span')`
  159. margin-left: ${space(0.5)};
  160. `;
  161. const GraphContainer = styled('div')`
  162. margin-bottom: ${space(3)};
  163. `;
  164. const StyledSidebarSectionContent = styled(SidebarSection.Content)`
  165. margin-top: ${space(0.5)};
  166. `;