index.tsx 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. import {useCallback, useMemo} from 'react';
  2. import styled from '@emotion/styled';
  3. import SearchBar from 'sentry/components/events/searchBar';
  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 {TransactionSearchQueryBuilder} from 'sentry/components/performance/transactionSearchQueryBuilder';
  9. import type {SmartSearchBarProps} from 'sentry/components/smartSearchBar';
  10. import {MAX_QUERY_LENGTH} from 'sentry/constants';
  11. import {t} from 'sentry/locale';
  12. import {space} from 'sentry/styles/space';
  13. import type {Organization} from 'sentry/types/organization';
  14. import {browserHistory} from 'sentry/utils/browserHistory';
  15. import EventView from 'sentry/utils/discover/eventView';
  16. import {isAggregateField} from 'sentry/utils/discover/fields';
  17. import {decodeScalar} from 'sentry/utils/queryString';
  18. import {MutableSearch} from 'sentry/utils/tokenizeSearch';
  19. import {useLocation} from 'sentry/utils/useLocation';
  20. import useOrganization from 'sentry/utils/useOrganization';
  21. import useProjects from 'sentry/utils/useProjects';
  22. import Tab from 'sentry/views/performance/transactionSummary/tabs';
  23. import PageLayout, {redirectToPerformanceHomepage} from '../pageLayout';
  24. import {TransactionProfilesContent} from './content';
  25. interface ProfilesProps {
  26. organization: Organization;
  27. transaction: string;
  28. }
  29. function Profiles({organization, transaction}: ProfilesProps) {
  30. const location = useLocation();
  31. const {projects} = useProjects();
  32. const project = projects.find(p => p.id === location.query.project);
  33. const rawQuery = useMemo(
  34. () => decodeScalar(location.query.query, ''),
  35. [location.query.query]
  36. );
  37. const query = useMemo(() => {
  38. const conditions = new MutableSearch(rawQuery);
  39. conditions.setFilterValues('event.type', ['transaction']);
  40. conditions.setFilterValues('transaction', [transaction]);
  41. Object.keys(conditions.filters).forEach(field => {
  42. if (isAggregateField(field)) {
  43. conditions.removeFilter(field);
  44. }
  45. });
  46. return conditions.formatString();
  47. }, [transaction, rawQuery]);
  48. const handleSearch: SmartSearchBarProps['onSearch'] = useCallback(
  49. (searchQuery: string) => {
  50. browserHistory.push({
  51. ...location,
  52. query: {
  53. ...location.query,
  54. cursor: undefined,
  55. query: searchQuery || undefined,
  56. },
  57. });
  58. },
  59. [location]
  60. );
  61. const projectIds = useMemo(
  62. () => (project ? [parseInt(project?.id, 10)] : undefined),
  63. [project]
  64. );
  65. return (
  66. <PageLayout
  67. location={location}
  68. organization={organization}
  69. projects={projects}
  70. tab={Tab.PROFILING}
  71. generateEventView={() => EventView.fromLocation(location)}
  72. getDocumentTitle={() => t(`Profile: %s`, transaction)}
  73. fillSpace
  74. childComponent={() => {
  75. return (
  76. <StyledMain fullWidth>
  77. <FilterActions>
  78. <PageFilterBar condensed>
  79. <EnvironmentPageFilter />
  80. <DatePageFilter />
  81. </PageFilterBar>
  82. {organization.features.includes('search-query-builder-performance') ? (
  83. <TransactionSearchQueryBuilder
  84. projects={projectIds}
  85. initialQuery={rawQuery}
  86. onSearch={handleSearch}
  87. searchSource="transaction_profiles"
  88. />
  89. ) : (
  90. <SearchBar
  91. searchSource="transaction_profiles"
  92. organization={organization}
  93. projectIds={projectIds}
  94. query={rawQuery}
  95. onSearch={handleSearch}
  96. maxQueryLength={MAX_QUERY_LENGTH}
  97. />
  98. )}
  99. </FilterActions>
  100. <TransactionProfilesContent query={query} transaction={transaction} />
  101. </StyledMain>
  102. );
  103. }}
  104. />
  105. );
  106. }
  107. const FilterActions = styled('div')`
  108. margin-bottom: ${space(2)};
  109. gap: ${space(2)};
  110. display: grid;
  111. grid-template-columns: min-content 1fr;
  112. `;
  113. const StyledMain = styled(Layout.Main)`
  114. display: flex;
  115. flex-direction: column;
  116. flex: 1;
  117. `;
  118. function ProfilesIndex() {
  119. const organization = useOrganization();
  120. const location = useLocation();
  121. const transaction = decodeScalar(location.query.transaction);
  122. if (!transaction) {
  123. redirectToPerformanceHomepage(organization, location);
  124. return null;
  125. }
  126. return <Profiles organization={organization} transaction={transaction} />;
  127. }
  128. export default ProfilesIndex;