content.tsx 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. import {useCallback, useMemo, useState} 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 CompactSelect from 'sentry/components/compactSelect';
  7. import * as Layout from 'sentry/components/layouts/thirds';
  8. import Pagination from 'sentry/components/pagination';
  9. import {FunctionsTable} from 'sentry/components/profiling/functionsTable';
  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 {useFunctions} from 'sentry/utils/profiling/hooks/useFunctions';
  15. import {useProfiles} from 'sentry/utils/profiling/hooks/useProfiles';
  16. import {decodeScalar} from 'sentry/utils/queryString';
  17. const FUNCTIONS_CURSOR_NAME = 'functionsCursor';
  18. const PROFILES_COLUMN_ORDER = [
  19. 'failed',
  20. 'id',
  21. 'timestamp',
  22. 'version_name',
  23. 'device_model',
  24. 'device_classification',
  25. 'trace_duration_ms',
  26. ] as const;
  27. interface ProfileSummaryContentProps {
  28. location: Location;
  29. project: Project;
  30. query: string;
  31. transaction: string;
  32. selection?: PageFilters;
  33. }
  34. function ProfileSummaryContent(props: ProfileSummaryContentProps) {
  35. const profilesCursor = useMemo(
  36. () => decodeScalar(props.location.query.cursor),
  37. [props.location.query.cursor]
  38. );
  39. const functionsCursor = useMemo(
  40. () => decodeScalar(props.location.query.functionsCursor),
  41. [props.location.query.functionsCursor]
  42. );
  43. const functionsSort = useMemo(
  44. () => decodeScalar(props.location.query.functionsSort, '-p99'),
  45. [props.location.query.functionsSort]
  46. );
  47. const profiles = useProfiles({
  48. cursor: profilesCursor,
  49. limit: 5,
  50. query: props.query,
  51. selection: props.selection,
  52. });
  53. const [functionType, setFunctionType] = useState<'application' | 'system' | 'all'>(
  54. 'application'
  55. );
  56. const functions = useFunctions({
  57. cursor: functionsCursor,
  58. project: props.project,
  59. query: props.query,
  60. selection: props.selection,
  61. transaction: props.transaction,
  62. sort: functionsSort,
  63. functionType,
  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. <TableHeader>
  87. <CompactSelect
  88. triggerProps={{prefix: t('Suspect Functions'), size: 'xs'}}
  89. value={functionType}
  90. options={[
  91. {
  92. label: t('All'),
  93. value: 'all' as const,
  94. },
  95. {
  96. label: t('Application'),
  97. value: 'application' as const,
  98. },
  99. {
  100. label: t('System'),
  101. value: 'system' as const,
  102. },
  103. ]}
  104. onChange={({value}) => setFunctionType(value)}
  105. />
  106. <StyledPagination
  107. pageLinks={functions.type === 'resolved' ? functions.data.pageLinks : null}
  108. onCursor={handleFunctionsCursor}
  109. size="xs"
  110. />
  111. </TableHeader>
  112. <FunctionsTable
  113. error={functions.type === 'errored' ? functions.error : null}
  114. isLoading={functions.type === 'initial' || functions.type === 'loading'}
  115. functions={functions.type === 'resolved' ? functions.data.functions : []}
  116. project={props.project}
  117. sort={functionsSort}
  118. />
  119. </Layout.Main>
  120. );
  121. }
  122. const TableHeader = styled('div')`
  123. display: flex;
  124. justify-content: space-between;
  125. margin-bottom: ${space(1)};
  126. `;
  127. const StyledPagination = styled(Pagination)`
  128. margin: 0 0 0 ${space(1)};
  129. `;
  130. export {ProfileSummaryContent};