suspectSpans.tsx 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. import {Fragment} from 'react';
  2. import styled from '@emotion/styled';
  3. import type {Location} from 'history';
  4. import {LinkButton} from 'sentry/components/button';
  5. import {SectionHeading} from 'sentry/components/charts/styles';
  6. import type {CursorHandler} from 'sentry/components/pagination';
  7. import Pagination from 'sentry/components/pagination';
  8. import {t} from 'sentry/locale';
  9. import {space} from 'sentry/styles/space';
  10. import type {Organization} from 'sentry/types/organization';
  11. import type EventView from 'sentry/utils/discover/eventView';
  12. import SuspectSpansQuery from 'sentry/utils/performance/suspectSpans/suspectSpansQuery';
  13. import {decodeScalar} from 'sentry/utils/queryString';
  14. import {useNavigate} from 'sentry/utils/useNavigate';
  15. import useProjects from 'sentry/utils/useProjects';
  16. import SuspectSpansTable from '../transactionSpans/suspectSpansTable';
  17. import type {SpansTotalValues} from '../transactionSpans/types';
  18. import {SpanSortOthers, SpanSortPercentiles} from '../transactionSpans/types';
  19. import {
  20. getSuspectSpanSortFromLocation,
  21. SPAN_SORT_TO_FIELDS,
  22. spansRouteWithQuery,
  23. } from '../transactionSpans/utils';
  24. const SPANS_CURSOR_NAME = 'spansCursor';
  25. type Props = {
  26. eventView: EventView;
  27. location: Location;
  28. organization: Organization;
  29. projectId: string;
  30. totals: SpansTotalValues | null;
  31. transactionName: string;
  32. };
  33. export default function SuspectSpans(props: Props) {
  34. const {location, organization, eventView, totals, projectId, transactionName} = props;
  35. const sort = getSuspectSpanSortFromLocation(location, 'spanSort');
  36. const cursor = decodeScalar(location.query?.[SPANS_CURSOR_NAME]);
  37. const sortedEventView = eventView
  38. .withColumns(
  39. [...Object.values(SpanSortOthers), ...Object.values(SpanSortPercentiles)].map(
  40. field => ({kind: 'field', field})
  41. )
  42. )
  43. .withSorts([{kind: 'desc', field: sort.field}]);
  44. const fields = SPAN_SORT_TO_FIELDS[sort.field];
  45. sortedEventView.fields = fields ? fields.map(field => ({field})) : [];
  46. const {projects} = useProjects();
  47. return (
  48. <SuspectSpansQuery
  49. location={location}
  50. orgSlug={organization.slug}
  51. eventView={sortedEventView}
  52. limit={4}
  53. perSuspect={0}
  54. cursor={cursor}
  55. >
  56. {({suspectSpans, isLoading, pageLinks}) => (
  57. <Fragment>
  58. <SuspectSpansHeader
  59. location={location}
  60. organization={organization}
  61. projectId={projectId}
  62. transactionName={transactionName}
  63. pageLinks={pageLinks}
  64. />
  65. <SuspectSpansTable
  66. location={location}
  67. organization={organization}
  68. transactionName={transactionName}
  69. project={projects.find(p => p.id === projectId)}
  70. isLoading={isLoading}
  71. suspectSpans={suspectSpans ?? []}
  72. totals={totals}
  73. sort={SpanSortOthers.SUM_EXCLUSIVE_TIME}
  74. />
  75. </Fragment>
  76. )}
  77. </SuspectSpansQuery>
  78. );
  79. }
  80. type HeaderProps = {
  81. location: Location;
  82. organization: Organization;
  83. pageLinks: string | null;
  84. projectId: string;
  85. transactionName: string;
  86. };
  87. function SuspectSpansHeader(props: HeaderProps) {
  88. const {location, organization, projectId, transactionName, pageLinks} = props;
  89. const navigate = useNavigate();
  90. const viewAllTarget = spansRouteWithQuery({
  91. orgSlug: organization.slug,
  92. transaction: transactionName,
  93. projectID: projectId,
  94. query: location.query,
  95. });
  96. const handleCursor: CursorHandler = (cursor, pathname, query) => {
  97. navigate({
  98. pathname,
  99. query: {...query, [SPANS_CURSOR_NAME]: cursor},
  100. });
  101. };
  102. return (
  103. <Header>
  104. <SectionHeading>{t('Suspect Spans')}</SectionHeading>
  105. <LinkButton to={viewAllTarget} size="xs" data-test-id="suspect-spans-open-tab">
  106. {t('View All Spans')}
  107. </LinkButton>
  108. <StyledPagination pageLinks={pageLinks} onCursor={handleCursor} size="xs" />
  109. </Header>
  110. );
  111. }
  112. const Header = styled('div')`
  113. display: grid;
  114. grid-template-columns: 1fr auto auto;
  115. margin-bottom: ${space(1)};
  116. align-items: center;
  117. `;
  118. const StyledPagination = styled(Pagination)`
  119. margin: 0 0 0 ${space(1)};
  120. `;