index.tsx 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. import {useCallback, useMemo} from 'react';
  2. import styled from '@emotion/styled';
  3. import omit from 'lodash/omit';
  4. import * as qs from 'query-string';
  5. import ProjectAvatar from 'sentry/components/avatar/projectAvatar';
  6. import Link from 'sentry/components/links/link';
  7. import {t} from 'sentry/locale';
  8. import {space} from 'sentry/styles/space';
  9. import {trackAnalytics} from 'sentry/utils/analytics';
  10. import {PageAlert, PageAlertProvider} from 'sentry/utils/performance/contexts/pageAlert';
  11. import {useLocation} from 'sentry/utils/useLocation';
  12. import useOrganization from 'sentry/utils/useOrganization';
  13. import useProjects from 'sentry/utils/useProjects';
  14. import useRouter from 'sentry/utils/useRouter';
  15. import {normalizeUrl} from 'sentry/utils/withDomainRequired';
  16. import {ScreenLoadSampleContainer} from 'sentry/views/performance/screenload/screenLoadSpans/samples/samplesContainer';
  17. import DetailPanel from 'sentry/views/starfish/components/detailPanel';
  18. import {useReleaseSelection} from 'sentry/views/starfish/queries/useReleases';
  19. type Props = {
  20. groupId: string;
  21. transactionName: string;
  22. additionalFilters?: Record<string, string>;
  23. onClose?: () => void;
  24. spanDescription?: string;
  25. spanOp?: string;
  26. transactionMethod?: string;
  27. transactionRoute?: string;
  28. };
  29. export function ScreenLoadSpanSamples({
  30. groupId,
  31. transactionName,
  32. transactionMethod,
  33. spanDescription,
  34. onClose,
  35. transactionRoute = '/performance/summary/',
  36. spanOp,
  37. additionalFilters,
  38. }: Props) {
  39. const router = useRouter();
  40. const {primaryRelease, secondaryRelease} = useReleaseSelection();
  41. // A a transaction name is required to show the panel, but a transaction
  42. // method is not
  43. const detailKey = transactionName
  44. ? [groupId, transactionName, transactionMethod].filter(Boolean).join(':')
  45. : undefined;
  46. const organization = useOrganization();
  47. const {query} = useLocation();
  48. const {projects} = useProjects();
  49. const project = useMemo(
  50. () => projects.find(p => p.id === String(query.project)),
  51. [projects, query.project]
  52. );
  53. const onOpenDetailPanel = useCallback(() => {
  54. if (query.transaction) {
  55. trackAnalytics('starfish.panel.open', {organization});
  56. }
  57. }, [organization, query.transaction]);
  58. const label =
  59. transactionMethod && !transactionName.startsWith(transactionMethod)
  60. ? `${transactionMethod} ${transactionName}`
  61. : transactionName;
  62. const link = normalizeUrl(
  63. `/organizations/${organization.slug}${transactionRoute}?${qs.stringify({
  64. project: query.project,
  65. transaction: transactionName,
  66. })}`
  67. );
  68. function defaultOnClose() {
  69. router.replace({
  70. pathname: router.location.pathname,
  71. query: omit(router.location.query, 'transaction', 'transactionMethod'),
  72. });
  73. }
  74. return (
  75. <PageAlertProvider>
  76. <DetailPanel
  77. detailKey={detailKey}
  78. onClose={() => {
  79. onClose ? onClose() : defaultOnClose();
  80. }}
  81. onOpen={onOpenDetailPanel}
  82. >
  83. <HeaderContainer>
  84. {project && (
  85. <SpanSummaryProjectAvatar
  86. project={project}
  87. direction="left"
  88. size={40}
  89. hasTooltip
  90. tooltip={project.slug}
  91. />
  92. )}
  93. <TitleContainer>
  94. {spanDescription && <SpanDescription>{spanDescription}</SpanDescription>}
  95. <Title>
  96. <Link to={link}>{label}</Link>
  97. </Title>
  98. </TitleContainer>
  99. </HeaderContainer>
  100. <PageAlert />
  101. <ChartsContainer>
  102. <ChartsContainerItem key="release1">
  103. <ScreenLoadSampleContainer
  104. groupId={groupId}
  105. transactionName={transactionName}
  106. transactionMethod={transactionMethod}
  107. release={primaryRelease}
  108. sectionTitle={t('Release 1')}
  109. project={project}
  110. spanOp={spanOp}
  111. additionalFilters={additionalFilters}
  112. />
  113. </ChartsContainerItem>
  114. <ChartsContainerItem key="release2">
  115. <ScreenLoadSampleContainer
  116. groupId={groupId}
  117. transactionName={transactionName}
  118. transactionMethod={transactionMethod}
  119. release={secondaryRelease}
  120. sectionTitle={t('Release 2')}
  121. project={project}
  122. spanOp={spanOp}
  123. additionalFilters={additionalFilters}
  124. />
  125. </ChartsContainerItem>
  126. </ChartsContainer>
  127. </DetailPanel>
  128. </PageAlertProvider>
  129. );
  130. }
  131. const SpanSummaryProjectAvatar = styled(ProjectAvatar)`
  132. padding-right: ${space(1)};
  133. `;
  134. const HeaderContainer = styled('div')`
  135. width: 100%;
  136. padding-bottom: ${space(2)};
  137. padding-top: ${space(1)};
  138. display: grid;
  139. grid-template-rows: auto auto auto;
  140. @media (min-width: ${p => p.theme.breakpoints.small}) {
  141. grid-template-rows: auto;
  142. grid-template-columns: auto 1fr auto;
  143. }
  144. `;
  145. const TitleContainer = styled('div')`
  146. width: 100%;
  147. position: relative;
  148. height: 40px;
  149. `;
  150. const Title = styled('h4')`
  151. position: absolute;
  152. bottom: 0;
  153. margin-bottom: 0;
  154. `;
  155. const SpanDescription = styled('div')`
  156. display: inline-block;
  157. white-space: nowrap;
  158. overflow: hidden;
  159. text-overflow: ellipsis;
  160. max-width: 35vw;
  161. `;
  162. const ChartsContainer = styled('div')`
  163. display: flex;
  164. flex-direction: row;
  165. gap: ${space(2)};
  166. align-items: top;
  167. `;
  168. const ChartsContainerItem = styled('div')`
  169. flex: 1;
  170. `;