suspectSpans.tsx 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. import {Fragment} from 'react';
  2. import {browserHistory} from 'react-router';
  3. import styled from '@emotion/styled';
  4. import type {Location} from 'history';
  5. import {Button} from 'sentry/components/button';
  6. import {SectionHeading} from 'sentry/components/charts/styles';
  7. import type {CursorHandler} from 'sentry/components/pagination';
  8. import Pagination from 'sentry/components/pagination';
  9. import {t} from 'sentry/locale';
  10. import {space} from 'sentry/styles/space';
  11. import type {Organization} from 'sentry/types';
  12. import type EventView from 'sentry/utils/discover/eventView';
  13. import SuspectSpansQuery from 'sentry/utils/performance/suspectSpans/suspectSpansQuery';
  14. import {decodeScalar} from 'sentry/utils/queryString';
  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 viewAllTarget = spansRouteWithQuery({
  90. orgSlug: organization.slug,
  91. transaction: transactionName,
  92. projectID: projectId,
  93. query: location.query,
  94. });
  95. const handleCursor: CursorHandler = (cursor, pathname, query) => {
  96. browserHistory.push({
  97. pathname,
  98. query: {...query, [SPANS_CURSOR_NAME]: cursor},
  99. });
  100. };
  101. return (
  102. <Header>
  103. <SectionHeading>{t('Suspect Spans')}</SectionHeading>
  104. <Button to={viewAllTarget} size="xs" data-test-id="suspect-spans-open-tab">
  105. {t('View All Spans')}
  106. </Button>
  107. <StyledPagination pageLinks={pageLinks} onCursor={handleCursor} size="xs" />
  108. </Header>
  109. );
  110. }
  111. const Header = styled('div')`
  112. display: grid;
  113. grid-template-columns: 1fr auto auto;
  114. margin-bottom: ${space(1)};
  115. align-items: center;
  116. `;
  117. const StyledPagination = styled(Pagination)`
  118. margin: 0 0 0 ${space(1)};
  119. `;