spanSamplesPanel.tsx 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. import styled from '@emotion/styled';
  2. import * as qs from 'query-string';
  3. import ProjectAvatar from 'sentry/components/avatar/projectAvatar';
  4. import {DrawerHeader} from 'sentry/components/globalDrawer/components';
  5. import Link from 'sentry/components/links/link';
  6. import {t} from 'sentry/locale';
  7. import {space} from 'sentry/styles/space';
  8. import {PageAlert, PageAlertProvider} from 'sentry/utils/performance/contexts/pageAlert';
  9. import {decodeScalar} from 'sentry/utils/queryString';
  10. import normalizeUrl from 'sentry/utils/url/normalizeUrl';
  11. import useLocationQuery from 'sentry/utils/url/useLocationQuery';
  12. import {useLocation} from 'sentry/utils/useLocation';
  13. import useOrganization from 'sentry/utils/useOrganization';
  14. import {SampleDrawerBody} from 'sentry/views/insights/common/components/sampleDrawerBody';
  15. import {useReleaseSelection} from 'sentry/views/insights/common/queries/useReleases';
  16. import {SpanSamplesContainer} from 'sentry/views/insights/mobile/common/components/spanSamplesPanelContainer';
  17. import useCrossPlatformProject from 'sentry/views/insights/mobile/common/queries/useCrossPlatformProject';
  18. import {useDomainViewFilters} from 'sentry/views/insights/pages/useFilters';
  19. import {type ModuleName, SpanMetricsField} from 'sentry/views/insights/types';
  20. import {getTransactionSummaryBaseUrl} from 'sentry/views/performance/transactionSummary/utils';
  21. type Props = {
  22. groupId: string;
  23. moduleName: ModuleName;
  24. transactionRoute?: string;
  25. };
  26. const PRIMARY_SPAN_QUERY_KEY = 'primarySpanSearchQuery';
  27. const SECONDARY_SPAN_QUERY_KEY = 'secondarySpanSearchQuery';
  28. export function SpanSamplesPanel({groupId, moduleName, transactionRoute}: Props) {
  29. const organization = useOrganization();
  30. const {view} = useDomainViewFilters();
  31. const {
  32. [SpanMetricsField.APP_START_TYPE]: appStartType,
  33. [SpanMetricsField.DEVICE_CLASS]: deviceClass,
  34. transaction: transactionName,
  35. transactionMethod,
  36. spanOp,
  37. spanDescription,
  38. } = useLocationQuery({
  39. fields: {
  40. [SpanMetricsField.APP_START_TYPE]: decodeScalar,
  41. [SpanMetricsField.DEVICE_CLASS]: decodeScalar,
  42. transaction: decodeScalar,
  43. transactionMethod: decodeScalar,
  44. spanOp: decodeScalar,
  45. spanDescription: decodeScalar,
  46. },
  47. });
  48. const additionalFilters = {
  49. ...(appStartType ? {[SpanMetricsField.APP_START_TYPE]: appStartType} : {}),
  50. ...(deviceClass ? {[SpanMetricsField.DEVICE_CLASS]: deviceClass} : {}),
  51. };
  52. transactionRoute ??= getTransactionSummaryBaseUrl(organization, view);
  53. const {primaryRelease, secondaryRelease} = useReleaseSelection();
  54. const {query} = useLocation();
  55. const {project} = useCrossPlatformProject();
  56. const label =
  57. transactionMethod && !transactionName.startsWith(transactionMethod)
  58. ? `${transactionMethod} ${transactionName}`
  59. : transactionName;
  60. const link = normalizeUrl(
  61. `/organizations/${organization.slug}${transactionRoute}?${qs.stringify({
  62. project: query.project,
  63. transaction: transactionName,
  64. })}`
  65. );
  66. return (
  67. <PageAlertProvider>
  68. <DrawerHeader />
  69. <SampleDrawerBody>
  70. <HeaderContainer>
  71. {project && (
  72. <SpanSummaryProjectAvatar
  73. project={project}
  74. direction="left"
  75. size={40}
  76. hasTooltip
  77. tooltip={project.slug}
  78. />
  79. )}
  80. <TitleContainer>
  81. {spanDescription && <SpanDescription>{spanDescription}</SpanDescription>}
  82. <Title>
  83. <Link to={link}>{label}</Link>
  84. </Title>
  85. </TitleContainer>
  86. </HeaderContainer>
  87. <PageAlert />
  88. <ChartsContainer>
  89. <ChartsContainerItem key="release1">
  90. <SpanSamplesContainer
  91. groupId={groupId}
  92. moduleName={moduleName}
  93. transactionName={transactionName}
  94. transactionMethod={transactionMethod}
  95. release={primaryRelease}
  96. sectionTitle={t('Release 1')}
  97. searchQueryKey={PRIMARY_SPAN_QUERY_KEY}
  98. spanOp={spanOp}
  99. additionalFilters={additionalFilters}
  100. />
  101. </ChartsContainerItem>
  102. <ChartsContainerItem key="release2">
  103. <SpanSamplesContainer
  104. groupId={groupId}
  105. moduleName={moduleName}
  106. transactionName={transactionName}
  107. transactionMethod={transactionMethod}
  108. release={secondaryRelease}
  109. sectionTitle={t('Release 2')}
  110. searchQueryKey={SECONDARY_SPAN_QUERY_KEY}
  111. spanOp={spanOp}
  112. additionalFilters={additionalFilters}
  113. />
  114. </ChartsContainerItem>
  115. </ChartsContainer>
  116. </SampleDrawerBody>
  117. </PageAlertProvider>
  118. );
  119. }
  120. const SpanSummaryProjectAvatar = styled(ProjectAvatar)`
  121. padding-right: ${space(1)};
  122. `;
  123. const HeaderContainer = styled('div')`
  124. width: 100%;
  125. padding-bottom: ${space(2)};
  126. padding-top: ${space(1)};
  127. display: grid;
  128. grid-template-rows: auto auto auto;
  129. @media (min-width: ${p => p.theme.breakpoints.small}) {
  130. grid-template-rows: auto;
  131. grid-template-columns: auto 1fr auto;
  132. }
  133. `;
  134. const TitleContainer = styled('div')`
  135. width: 100%;
  136. position: relative;
  137. height: 40px;
  138. `;
  139. const Title = styled('h4')`
  140. position: absolute;
  141. bottom: 0;
  142. margin-bottom: 0;
  143. `;
  144. const SpanDescription = styled('div')`
  145. display: inline-block;
  146. white-space: nowrap;
  147. overflow: hidden;
  148. text-overflow: ellipsis;
  149. max-width: 35vw;
  150. `;
  151. const ChartsContainer = styled('div')`
  152. display: flex;
  153. flex-direction: row;
  154. gap: ${space(2)};
  155. align-items: top;
  156. `;
  157. const ChartsContainerItem = styled('div')`
  158. flex: 1;
  159. `;