functionsMiniGrid.tsx 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. import {CSSProperties, Fragment, SyntheticEvent} from 'react';
  2. import styled from '@emotion/styled';
  3. import Link from 'sentry/components/links/link';
  4. import LoadingIndicator from 'sentry/components/loadingIndicator';
  5. import PerformanceDuration from 'sentry/components/performanceDuration';
  6. import {Flex} from 'sentry/components/profiling/flex';
  7. import {t} from 'sentry/locale';
  8. import {space} from 'sentry/styles/space';
  9. import {Organization, Project} from 'sentry/types';
  10. import {defined} from 'sentry/utils';
  11. import {EventsResults} from 'sentry/utils/profiling/hooks/types';
  12. import {generateProfileFlamechartRouteWithHighlightFrame} from 'sentry/utils/profiling/routes';
  13. const functionsFields = [
  14. 'package',
  15. 'function',
  16. 'count()',
  17. 'sum()',
  18. 'examples()',
  19. ] as const;
  20. type FunctionsField = (typeof functionsFields)[number];
  21. interface FunctionsMiniGridProps {
  22. functions: EventsResults<FunctionsField>['data'];
  23. onLinkClick: (e: SyntheticEvent) => void;
  24. organization: Organization;
  25. project: Project;
  26. }
  27. export function FunctionsMiniGrid(props: FunctionsMiniGridProps) {
  28. const {organization, project, functions, onLinkClick} = props;
  29. const linkToFlamechartRoute = (
  30. profileId: string,
  31. frameName: string,
  32. framePackage: string
  33. ) => {
  34. return generateProfileFlamechartRouteWithHighlightFrame({
  35. orgSlug: organization.slug,
  36. projectSlug: project.slug,
  37. profileId,
  38. frameName,
  39. framePackage,
  40. });
  41. };
  42. return (
  43. <FunctionsMiniGridContainer>
  44. <FunctionsMiniGridHeader>{t('Slowest app functions')}</FunctionsMiniGridHeader>
  45. <FunctionsMiniGridHeader align="right">
  46. {t('Total Self Time')}
  47. </FunctionsMiniGridHeader>
  48. <FunctionsMiniGridHeader align="right">{t('Count')}</FunctionsMiniGridHeader>
  49. {functions &&
  50. functions.map((f, idx) => {
  51. if (!defined(f)) {
  52. return null;
  53. }
  54. const exampleProfileIdRaw = f['examples()']![0];
  55. const exampleProfileId = exampleProfileIdRaw.replaceAll('-', '');
  56. return (
  57. <Fragment key={idx}>
  58. <FunctionsMiniGridCell title={f.function as string}>
  59. <FunctionNameTextTruncate>
  60. <Link
  61. to={linkToFlamechartRoute(
  62. exampleProfileId,
  63. f.function as string,
  64. f.package as string
  65. )}
  66. onClick={onLinkClick}
  67. >
  68. {f.function}
  69. </Link>
  70. </FunctionNameTextTruncate>
  71. </FunctionsMiniGridCell>
  72. <FunctionsMiniGridCell align="right">
  73. <PerformanceDuration nanoseconds={f['sum()'] as number} abbreviation />
  74. </FunctionsMiniGridCell>
  75. <FunctionsMiniGridCell align="right">
  76. <NumberContainer>{f['count()']}</NumberContainer>
  77. </FunctionsMiniGridCell>
  78. </Fragment>
  79. );
  80. })}
  81. </FunctionsMiniGridContainer>
  82. );
  83. }
  84. export function FunctionsMiniGridLoading() {
  85. return (
  86. <Flex align="stretch" justify="center" column h="100%">
  87. <Flex align="center" justify="center">
  88. <LoadingIndicator mini />
  89. </Flex>
  90. </Flex>
  91. );
  92. }
  93. export function FunctionsMiniGridEmptyState() {
  94. return (
  95. <Flex align="stretch" justify="center" column h="100%">
  96. <Flex align="center" justify="center">
  97. {t('No functions data')}
  98. </Flex>
  99. </Flex>
  100. );
  101. }
  102. export const FunctionsMiniGridContainer = styled('div')`
  103. display: grid;
  104. grid-template-columns: 60% 20% 20%;
  105. `;
  106. export const FunctionsMiniGridHeader = styled('span')<{
  107. align?: CSSProperties['textAlign'];
  108. }>`
  109. text-transform: uppercase;
  110. font-size: ${p => p.theme.fontSizeExtraSmall};
  111. font-weight: 600;
  112. color: ${p => p.theme.subText};
  113. text-align: ${p => p.align};
  114. `;
  115. export const FunctionsMiniGridCell = styled('div')<{align?: CSSProperties['textAlign']}>`
  116. font-size: ${p => p.theme.fontSizeSmall};
  117. text-align: ${p => p.align};
  118. padding: ${space(0.5)} 0px;
  119. `;
  120. const NumberContainer = styled(`div`)`
  121. text-align: right;
  122. `;
  123. const FunctionNameTextTruncate = styled('div')`
  124. min-width: 0;
  125. overflow: hidden;
  126. white-space: nowrap;
  127. text-overflow: ellipsis;
  128. `;