releaseStats.tsx 5.9 KB

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