index.tsx 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. import styled from '@emotion/styled';
  2. import {Breadcrumbs} from 'sentry/components/breadcrumbs';
  3. import FloatingFeedbackWidget from 'sentry/components/feedback/widget/floatingFeedbackWidget';
  4. import * as Layout from 'sentry/components/layouts/thirds';
  5. import {DatePageFilter} from 'sentry/components/organizations/datePageFilter';
  6. import {EnvironmentPageFilter} from 'sentry/components/organizations/environmentPageFilter';
  7. import PageFilterBar from 'sentry/components/organizations/pageFilterBar';
  8. import {ProjectPageFilter} from 'sentry/components/organizations/projectPageFilter';
  9. import {t} from 'sentry/locale';
  10. import {useLocation} from 'sentry/utils/useLocation';
  11. import useOrganization from 'sentry/utils/useOrganization';
  12. import {useParams} from 'sentry/utils/useParams';
  13. import {normalizeUrl} from 'sentry/utils/withDomainRequired';
  14. import ResourceInfo from 'sentry/views/performance/browser/resources/resourceSummaryPage/resourceInfo';
  15. import ResourceSummaryCharts from 'sentry/views/performance/browser/resources/resourceSummaryPage/resourceSummaryCharts';
  16. import ResourceSummaryTable from 'sentry/views/performance/browser/resources/resourceSummaryPage/resourceSummaryTable';
  17. import SampleImages from 'sentry/views/performance/browser/resources/resourceSummaryPage/sampleImages';
  18. import {FilterOptionsContainer} from 'sentry/views/performance/browser/resources/resourceView';
  19. import {IMAGE_FILE_EXTENSIONS} from 'sentry/views/performance/browser/resources/shared/constants';
  20. import RenderBlockingSelector from 'sentry/views/performance/browser/resources/shared/renderBlockingSelector';
  21. import {ResourceSpanOps} from 'sentry/views/performance/browser/resources/shared/types';
  22. import {useResourceModuleFilters} from 'sentry/views/performance/browser/resources/utils/useResourceFilters';
  23. import {ModulePageProviders} from 'sentry/views/performance/modulePageProviders';
  24. import {useSpanMetrics} from 'sentry/views/starfish/queries/useSpanMetrics';
  25. import {SpanMetricsField} from 'sentry/views/starfish/types';
  26. import {SampleList} from 'sentry/views/starfish/views/spanSummaryPage/sampleList';
  27. const {
  28. SPAN_SELF_TIME,
  29. SPAN_DESCRIPTION,
  30. HTTP_DECODED_RESPONSE_CONTENT_LENGTH,
  31. HTTP_RESPONSE_CONTENT_LENGTH,
  32. HTTP_RESPONSE_TRANSFER_SIZE,
  33. RESOURCE_RENDER_BLOCKING_STATUS,
  34. SPAN_OP,
  35. } = SpanMetricsField;
  36. function ResourceSummary() {
  37. const organization = useOrganization();
  38. const {groupId} = useParams();
  39. const filters = useResourceModuleFilters();
  40. const selectedSpanOp = filters[SPAN_OP];
  41. const {
  42. query: {transaction},
  43. } = useLocation();
  44. const {data} = useSpanMetrics({
  45. filters: {
  46. 'span.group': groupId,
  47. },
  48. fields: [
  49. `avg(${SPAN_SELF_TIME})`,
  50. `avg(${HTTP_RESPONSE_CONTENT_LENGTH})`,
  51. `avg(${HTTP_DECODED_RESPONSE_CONTENT_LENGTH})`,
  52. `avg(${HTTP_RESPONSE_TRANSFER_SIZE})`,
  53. `sum(${SPAN_SELF_TIME})`,
  54. 'spm()',
  55. SPAN_OP,
  56. SPAN_DESCRIPTION,
  57. 'time_spent_percentage()',
  58. 'project.id',
  59. ],
  60. });
  61. const spanMetrics = selectedSpanOp
  62. ? data.find(item => item[SPAN_OP] === selectedSpanOp) ?? {}
  63. : data[0] ?? {};
  64. const uniqueSpanOps = new Set(data.map(item => item[SPAN_OP]));
  65. const isImage =
  66. filters[SPAN_OP] === ResourceSpanOps.IMAGE ||
  67. IMAGE_FILE_EXTENSIONS.includes(
  68. spanMetrics[SpanMetricsField.SPAN_DESCRIPTION]?.split('.').pop() || ''
  69. ) ||
  70. (uniqueSpanOps.size === 1 && spanMetrics[SPAN_OP] === ResourceSpanOps.IMAGE);
  71. return (
  72. <ModulePageProviders
  73. title={[t('Performance'), t('Resources'), t('Resource Summary')].join(' — ')}
  74. baseURL="/performance/browser/resources"
  75. features="starfish-browser-resource-module-ui"
  76. >
  77. <Layout.Header>
  78. <Layout.HeaderContent>
  79. <Breadcrumbs
  80. crumbs={[
  81. {
  82. label: 'Performance',
  83. to: normalizeUrl(`/organizations/${organization.slug}/performance/`),
  84. preservePageFilters: true,
  85. },
  86. {
  87. label: 'Resources',
  88. to: normalizeUrl(
  89. `/organizations/${organization.slug}/performance/browser/resources/`
  90. ),
  91. preservePageFilters: true,
  92. },
  93. {
  94. label: 'Resource Summary',
  95. },
  96. ]}
  97. />
  98. <Layout.Title>{spanMetrics[SpanMetricsField.SPAN_DESCRIPTION]}</Layout.Title>
  99. </Layout.HeaderContent>
  100. </Layout.Header>
  101. <Layout.Body>
  102. <Layout.Main fullWidth>
  103. <FloatingFeedbackWidget />
  104. <HeaderContainer>
  105. <FilterOptionsContainer columnCount={2}>
  106. <PageFilterBar condensed>
  107. <ProjectPageFilter />
  108. <EnvironmentPageFilter />
  109. <DatePageFilter />
  110. </PageFilterBar>
  111. <RenderBlockingSelector
  112. value={filters[RESOURCE_RENDER_BLOCKING_STATUS] || ''}
  113. />
  114. </FilterOptionsContainer>
  115. <ResourceInfo
  116. avgContentLength={spanMetrics[`avg(${HTTP_RESPONSE_CONTENT_LENGTH})`]}
  117. avgDecodedContentLength={
  118. spanMetrics[`avg(${HTTP_DECODED_RESPONSE_CONTENT_LENGTH})`]
  119. }
  120. avgTransferSize={spanMetrics[`avg(${HTTP_RESPONSE_TRANSFER_SIZE})`]}
  121. avgDuration={spanMetrics[`avg(${SPAN_SELF_TIME})`]}
  122. throughput={spanMetrics['spm()']}
  123. timeSpentTotal={spanMetrics[`sum(${SPAN_SELF_TIME})`]}
  124. timeSpentPercentage={spanMetrics[`time_spent_percentage()`]}
  125. spanOp={spanMetrics[SPAN_OP]}
  126. />
  127. </HeaderContainer>
  128. {isImage && (
  129. <SampleImages groupId={groupId} projectId={data?.[0]?.['project.id']} />
  130. )}
  131. <ResourceSummaryCharts groupId={groupId} />
  132. <ResourceSummaryTable />
  133. <SampleList
  134. transactionRoute="/performance/browser/pageloads/"
  135. groupId={groupId}
  136. transactionName={transaction as string}
  137. additionalFields={[HTTP_RESPONSE_CONTENT_LENGTH]}
  138. />
  139. </Layout.Main>
  140. </Layout.Body>
  141. </ModulePageProviders>
  142. );
  143. }
  144. const HeaderContainer = styled('div')`
  145. display: flex;
  146. justify-content: space-between;
  147. flex-wrap: wrap;
  148. `;
  149. export default ResourceSummary;