httpLandingPage.tsx 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. import React, {Fragment} from 'react';
  2. import styled from '@emotion/styled';
  3. import pickBy from 'lodash/pickBy';
  4. import {Breadcrumbs} from 'sentry/components/breadcrumbs';
  5. import FloatingFeedbackWidget from 'sentry/components/feedback/widget/floatingFeedbackWidget';
  6. import * as Layout from 'sentry/components/layouts/thirds';
  7. import {DatePageFilter} from 'sentry/components/organizations/datePageFilter';
  8. import {EnvironmentPageFilter} from 'sentry/components/organizations/environmentPageFilter';
  9. import PageFilterBar from 'sentry/components/organizations/pageFilterBar';
  10. import {ProjectPageFilter} from 'sentry/components/organizations/projectPageFilter';
  11. import {t} from 'sentry/locale';
  12. import {space} from 'sentry/styles/space';
  13. import {fromSorts} from 'sentry/utils/discover/eventView';
  14. import {decodeScalar} from 'sentry/utils/queryString';
  15. import {useLocation} from 'sentry/utils/useLocation';
  16. import useOrganization from 'sentry/utils/useOrganization';
  17. import {normalizeUrl} from 'sentry/utils/withDomainRequired';
  18. import {useOnboardingProject} from 'sentry/views/performance/browser/webVitals/utils/useOnboardingProject';
  19. import {DurationChart} from 'sentry/views/performance/database/durationChart';
  20. import {ModulePageProviders} from 'sentry/views/performance/database/modulePageProviders';
  21. import {DomainsTable, isAValidSort} from 'sentry/views/performance/http/domainsTable';
  22. import {ThroughputChart} from 'sentry/views/performance/http/throughputChart';
  23. import Onboarding from 'sentry/views/performance/onboarding';
  24. import {useSynchronizeCharts} from 'sentry/views/starfish/components/chart';
  25. import {useSpanMetrics} from 'sentry/views/starfish/queries/useSpanMetrics';
  26. import {useSpanMetricsSeries} from 'sentry/views/starfish/queries/useSpanMetricsSeries';
  27. import {ModuleName} from 'sentry/views/starfish/types';
  28. import {QueryParameterNames} from 'sentry/views/starfish/views/queryParameters';
  29. export function HTTPLandingPage() {
  30. const organization = useOrganization();
  31. const location = useLocation();
  32. const onboardingProject = useOnboardingProject();
  33. const sortField = decodeScalar(location.query?.[QueryParameterNames.DOMAINS_SORT]);
  34. const sort = fromSorts(sortField).filter(isAValidSort).at(0) ?? DEFAULT_SORT;
  35. const chartFilters = {
  36. 'span.module': ModuleName.HTTP,
  37. has: 'span.domain',
  38. };
  39. const tableFilters = {
  40. 'span.module': ModuleName.HTTP,
  41. has: 'span.domain',
  42. };
  43. const cursor = decodeScalar(location.query?.[QueryParameterNames.DOMAINS_CURSOR]);
  44. const {isLoading: isThroughputDataLoading, data: throughputData} = useSpanMetricsSeries(
  45. {
  46. filters: chartFilters,
  47. yAxis: ['spm()'],
  48. referrer: 'api.starfish.http-module-landing-throughput-chart',
  49. }
  50. );
  51. const {isLoading: isDurationDataLoading, data: durationData} = useSpanMetricsSeries({
  52. filters: chartFilters,
  53. yAxis: [`avg(span.self_time)`],
  54. referrer: 'api.starfish.http-module-landing-duration-chart',
  55. });
  56. const domainsListResponse = useSpanMetrics({
  57. filters: pickBy(tableFilters, value => value !== undefined),
  58. fields: [
  59. 'project.id',
  60. 'span.domain',
  61. 'spm()',
  62. 'avg(span.self_time)',
  63. 'sum(span.self_time)',
  64. 'time_spent_percentage()',
  65. ],
  66. sorts: [sort],
  67. limit: DOMAIN_TABLE_ROW_COUNT,
  68. cursor,
  69. referrer: 'api.starfish.http-module-domains-list',
  70. });
  71. useSynchronizeCharts([!isThroughputDataLoading && !isDurationDataLoading]);
  72. return (
  73. <React.Fragment>
  74. <Layout.Header>
  75. <Layout.HeaderContent>
  76. <Breadcrumbs
  77. crumbs={[
  78. {
  79. label: t('Performance'),
  80. to: normalizeUrl(`/organizations/${organization.slug}/performance/`),
  81. preservePageFilters: true,
  82. },
  83. {
  84. label: t('HTTP'),
  85. },
  86. ]}
  87. />
  88. <Layout.Title>{t('HTTP')}</Layout.Title>
  89. </Layout.HeaderContent>
  90. </Layout.Header>
  91. <Layout.Body>
  92. <Layout.Main fullWidth>
  93. <FloatingFeedbackWidget />
  94. <PaddedContainer>
  95. <PageFilterBar condensed>
  96. <ProjectPageFilter />
  97. <EnvironmentPageFilter />
  98. <DatePageFilter />
  99. </PageFilterBar>
  100. </PaddedContainer>
  101. {onboardingProject && (
  102. <Onboarding organization={organization} project={onboardingProject} />
  103. )}
  104. {!onboardingProject && (
  105. <Fragment>
  106. <ChartContainer>
  107. <ThroughputChart
  108. series={throughputData['spm()']}
  109. isLoading={isThroughputDataLoading}
  110. />
  111. <DurationChart
  112. series={durationData[`avg(span.self_time)`]}
  113. isLoading={isDurationDataLoading}
  114. />
  115. </ChartContainer>
  116. <DomainsTable response={domainsListResponse} sort={sort} />
  117. </Fragment>
  118. )}
  119. </Layout.Main>
  120. </Layout.Body>
  121. </React.Fragment>
  122. );
  123. }
  124. const DEFAULT_SORT = {
  125. field: 'time_spent_percentage()' as const,
  126. kind: 'desc' as const,
  127. };
  128. const PaddedContainer = styled('div')`
  129. margin-bottom: ${space(2)};
  130. `;
  131. const ChartContainer = styled('div')`
  132. display: grid;
  133. grid-template-columns: 1fr;
  134. @media (min-width: ${p => p.theme.breakpoints.small}) {
  135. grid-template-columns: 1fr 1fr;
  136. gap: ${space(2)};
  137. }
  138. `;
  139. const DOMAIN_TABLE_ROW_COUNT = 10;
  140. function LandingPageWithProviders() {
  141. return (
  142. <ModulePageProviders title={[t('Performance'), t('HTTP')].join(' — ')}>
  143. <HTTPLandingPage />
  144. </ModulePageProviders>
  145. );
  146. }
  147. export default LandingPageWithProviders;