content.tsx 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. import {useCallback, useState} from 'react';
  2. import styled from '@emotion/styled';
  3. import type {Location} from 'history';
  4. import Feature from 'sentry/components/acl/feature';
  5. import {Alert} from 'sentry/components/alert';
  6. import {Button} from 'sentry/components/button';
  7. import ButtonBar from 'sentry/components/buttonBar';
  8. import FeedbackWidgetButton from 'sentry/components/feedback/widget/feedbackWidgetButton';
  9. import * as Layout from 'sentry/components/layouts/thirds';
  10. import {DatePageFilter} from 'sentry/components/organizations/datePageFilter';
  11. import {EnvironmentPageFilter} from 'sentry/components/organizations/environmentPageFilter';
  12. import PageFilterBar from 'sentry/components/organizations/pageFilterBar';
  13. import PageFiltersContainer from 'sentry/components/organizations/pageFilters/container';
  14. import {ProjectPageFilter} from 'sentry/components/organizations/projectPageFilter';
  15. import {
  16. EAPSpanSearchQueryBuilder,
  17. SpanSearchQueryBuilder,
  18. } from 'sentry/components/performance/spanSearchQueryBuilder';
  19. import SentryDocumentTitle from 'sentry/components/sentryDocumentTitle';
  20. import {t} from 'sentry/locale';
  21. import {space} from 'sentry/styles/space';
  22. import {DiscoverDatasets} from 'sentry/utils/discover/types';
  23. import {ALLOWED_EXPLORE_VISUALIZE_AGGREGATES} from 'sentry/utils/fields';
  24. import {useLocation} from 'sentry/utils/useLocation';
  25. import {useNavigate} from 'sentry/utils/useNavigate';
  26. import useOrganization from 'sentry/utils/useOrganization';
  27. import usePageFilters from 'sentry/utils/usePageFilters';
  28. import {ExploreCharts} from 'sentry/views/explore/charts';
  29. import {
  30. SpanTagsProvider,
  31. useSpanTags,
  32. } from 'sentry/views/explore/contexts/spanTagsContext';
  33. import {useDataset} from 'sentry/views/explore/hooks/useDataset';
  34. import {useUserQuery} from 'sentry/views/explore/hooks/useUserQuery';
  35. import {ExploreTables} from 'sentry/views/explore/tables';
  36. import {ExploreToolbar} from 'sentry/views/explore/toolbar';
  37. import {useResultMode} from './hooks/useResultsMode';
  38. interface ExploreContentProps {
  39. location: Location;
  40. }
  41. function ExploreContentImpl({}: ExploreContentProps) {
  42. const location = useLocation();
  43. const navigate = useNavigate();
  44. const organization = useOrganization();
  45. const {selection} = usePageFilters();
  46. const [dataset] = useDataset();
  47. const [resultMode] = useResultMode();
  48. const supportedAggregates =
  49. resultMode === 'aggregate' ? ALLOWED_EXPLORE_VISUALIZE_AGGREGATES : [];
  50. const numberTags = useSpanTags('number');
  51. const stringTags = useSpanTags('string');
  52. const [userQuery, setUserQuery] = useUserQuery();
  53. const toolbarExtras = organization.features.includes('visibility-explore-dataset')
  54. ? ['dataset toggle' as const]
  55. : [];
  56. const switchToOldTraceExplorer = useCallback(() => {
  57. navigate({
  58. ...location,
  59. query: {
  60. ...location.query,
  61. view: 'trace',
  62. },
  63. });
  64. }, [location, navigate]);
  65. const [chartError, setChartError] = useState<string>('');
  66. const [tableError, setTableError] = useState<string>('');
  67. const maxPickableDays = 7;
  68. return (
  69. <SentryDocumentTitle title={t('Traces')} orgSlug={organization.slug}>
  70. <PageFiltersContainer maxPickableDays={maxPickableDays}>
  71. <Layout.Page>
  72. <Layout.Header>
  73. <Layout.HeaderContent>
  74. <Layout.Title>{t('Traces')}</Layout.Title>
  75. </Layout.HeaderContent>
  76. <Layout.HeaderActions>
  77. <ButtonBar gap={1}>
  78. <Feature organization={organization} features="visibility-explore-admin">
  79. <Button onClick={switchToOldTraceExplorer} size="sm">
  80. {t('Switch to Old Trace Explore')}
  81. </Button>
  82. </Feature>
  83. <FeedbackWidgetButton />
  84. </ButtonBar>
  85. </Layout.HeaderActions>
  86. </Layout.Header>
  87. <Body>
  88. <TopSection>
  89. <StyledPageFilterBar condensed>
  90. <ProjectPageFilter />
  91. <EnvironmentPageFilter />
  92. <DatePageFilter
  93. defaultPeriod="7d"
  94. maxPickableDays={maxPickableDays}
  95. relativeOptions={({arbitraryOptions}) => ({
  96. ...arbitraryOptions,
  97. '1h': t('Last 1 hour'),
  98. '24h': t('Last 24 hours'),
  99. '7d': t('Last 7 days'),
  100. })}
  101. />
  102. </StyledPageFilterBar>
  103. {dataset === DiscoverDatasets.SPANS_INDEXED ? (
  104. <SpanSearchQueryBuilder
  105. projects={selection.projects}
  106. initialQuery={userQuery}
  107. onSearch={setUserQuery}
  108. searchSource="explore"
  109. />
  110. ) : (
  111. <EAPSpanSearchQueryBuilder
  112. projects={selection.projects}
  113. initialQuery={userQuery}
  114. onSearch={setUserQuery}
  115. searchSource="explore"
  116. supportedAggregates={supportedAggregates}
  117. numberTags={numberTags}
  118. stringTags={stringTags}
  119. />
  120. )}
  121. </TopSection>
  122. <ExploreToolbar extras={toolbarExtras} />
  123. <MainSection fullWidth>
  124. {(tableError || chartError) && (
  125. <Alert type="error" showIcon>
  126. {tableError || chartError}
  127. </Alert>
  128. )}
  129. <ExploreCharts query={userQuery} setError={setChartError} />
  130. <ExploreTables setError={setTableError} />
  131. </MainSection>
  132. </Body>
  133. </Layout.Page>
  134. </PageFiltersContainer>
  135. </SentryDocumentTitle>
  136. );
  137. }
  138. export function ExploreContent(props: ExploreContentProps) {
  139. const [dataset] = useDataset();
  140. return (
  141. <SpanTagsProvider dataset={dataset} enabled>
  142. <ExploreContentImpl {...props} />
  143. </SpanTagsProvider>
  144. );
  145. }
  146. const Body = styled(Layout.Body)`
  147. gap: ${space(2)};
  148. @media (min-width: ${p => p.theme.breakpoints.medium}) {
  149. grid-template-columns: 350px minmax(100px, auto);
  150. gap: ${space(2)};
  151. }
  152. @media (min-width: ${p => p.theme.breakpoints.xxlarge}) {
  153. grid-template-columns: 400px minmax(100px, auto);
  154. }
  155. `;
  156. const TopSection = styled('div')`
  157. display: grid;
  158. gap: ${space(2)};
  159. grid-column: 1/3;
  160. margin-bottom: ${space(2)};
  161. @media (min-width: ${p => p.theme.breakpoints.large}) {
  162. grid-template-columns: minmax(350px, auto) 1fr;
  163. margin-bottom: 0;
  164. }
  165. @media (min-width: ${p => p.theme.breakpoints.xxlarge}) {
  166. grid-template-columns: minmax(400px, auto) 1fr;
  167. }
  168. `;
  169. const MainSection = styled(Layout.Main)`
  170. grid-column: 2/3;
  171. `;
  172. const StyledPageFilterBar = styled(PageFilterBar)`
  173. width: auto;
  174. `;