content.tsx 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. import {Fragment, useCallback, useMemo} from 'react';
  2. import {browserHistory} from 'react-router';
  3. import styled from '@emotion/styled';
  4. import {Location} from 'history';
  5. import {SectionHeading} from 'sentry/components/charts/styles';
  6. import * as Layout from 'sentry/components/layouts/thirds';
  7. import Pagination from 'sentry/components/pagination';
  8. import {FunctionsTable} from 'sentry/components/profiling/functionsTable';
  9. import {LegacyFunctionsTable} from 'sentry/components/profiling/legacyFunctionsTable';
  10. import {ProfilesTable} from 'sentry/components/profiling/profilesTable';
  11. import {t} from 'sentry/locale';
  12. import space from 'sentry/styles/space';
  13. import {PageFilters, Project} from 'sentry/types';
  14. import {
  15. isFunctionsResultV1,
  16. isFunctionsResultV2,
  17. useFunctions,
  18. } from 'sentry/utils/profiling/hooks/useFunctions';
  19. import {useProfiles} from 'sentry/utils/profiling/hooks/useProfiles';
  20. import {decodeScalar} from 'sentry/utils/queryString';
  21. const FUNCTIONS_CURSOR_NAME = 'functionsCursor';
  22. const PROFILES_COLUMN_ORDER = [
  23. 'failed',
  24. 'id',
  25. 'timestamp',
  26. 'version_name',
  27. 'device_model',
  28. 'device_classification',
  29. 'trace_duration_ms',
  30. ] as const;
  31. interface ProfileSummaryContentProps {
  32. location: Location;
  33. project: Project;
  34. query: string;
  35. transaction: string;
  36. selection?: PageFilters;
  37. }
  38. function ProfileSummaryContent(props: ProfileSummaryContentProps) {
  39. const profilesCursor = useMemo(
  40. () => decodeScalar(props.location.query.cursor),
  41. [props.location.query.cursor]
  42. );
  43. const functionsCursor = useMemo(
  44. () => decodeScalar(props.location.query.functionsCursor),
  45. [props.location.query.functionsCursor]
  46. );
  47. const functionsSort = useMemo(
  48. () => decodeScalar(props.location.query.functionsSort, '-p99'),
  49. [props.location.query.functionsSort]
  50. );
  51. const profiles = useProfiles({
  52. cursor: profilesCursor,
  53. limit: 5,
  54. query: props.query,
  55. selection: props.selection,
  56. });
  57. const functions = useFunctions({
  58. cursor: functionsCursor,
  59. project: props.project,
  60. query: props.query,
  61. selection: props.selection,
  62. transaction: props.transaction,
  63. sort: functionsSort,
  64. });
  65. const handleFunctionsCursor = useCallback((cursor, pathname, query) => {
  66. browserHistory.push({
  67. pathname,
  68. query: {...query, [FUNCTIONS_CURSOR_NAME]: cursor},
  69. });
  70. }, []);
  71. return (
  72. <Layout.Main fullWidth>
  73. <TableHeader>
  74. <SectionHeading>{t('Recent Profiles')}</SectionHeading>
  75. <StyledPagination
  76. pageLinks={profiles.type === 'resolved' ? profiles.data.pageLinks : null}
  77. size="xs"
  78. />
  79. </TableHeader>
  80. <ProfilesTable
  81. error={profiles.type === 'errored' ? profiles.error : null}
  82. isLoading={profiles.type === 'initial' || profiles.type === 'loading'}
  83. traces={profiles.type === 'resolved' ? profiles.data.traces : []}
  84. columnOrder={PROFILES_COLUMN_ORDER}
  85. />
  86. {functions.type === 'resolved' && isFunctionsResultV1(functions.data) ? (
  87. // this does result in some flickering if we get the v1 results
  88. // back but this is temporary and will be removed in the near future
  89. <LegacyFunctionsTable
  90. error={null}
  91. functionCalls={functions.data.functions}
  92. isLoading={false}
  93. project={props.project}
  94. />
  95. ) : (
  96. <Fragment>
  97. <TableHeader>
  98. <SectionHeading>{t('Suspect Functions')}</SectionHeading>
  99. <StyledPagination
  100. pageLinks={
  101. functions.type === 'resolved' && isFunctionsResultV2(functions.data)
  102. ? functions.data.pageLinks
  103. : null
  104. }
  105. onCursor={handleFunctionsCursor}
  106. size="xs"
  107. />
  108. </TableHeader>
  109. <FunctionsTable
  110. error={functions.type === 'errored' ? functions.error : null}
  111. isLoading={functions.type === 'initial' || functions.type === 'loading'}
  112. functions={
  113. functions.type === 'resolved' && isFunctionsResultV2(functions.data)
  114. ? functions.data.functions
  115. : []
  116. }
  117. project={props.project}
  118. sort={functionsSort}
  119. />
  120. </Fragment>
  121. )}
  122. </Layout.Main>
  123. );
  124. }
  125. const TableHeader = styled('div')`
  126. display: flex;
  127. justify-content: space-between;
  128. margin-bottom: ${space(1)};
  129. `;
  130. const StyledPagination = styled(Pagination)`
  131. margin: 0 0 0 ${space(1)};
  132. `;
  133. export {ProfileSummaryContent};