releaseStats.tsx 5.8 KB

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