eventDetailsHeader.tsx 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. import styled from '@emotion/styled';
  2. import {LinkButton} from 'sentry/components/button';
  3. import {Flex} from 'sentry/components/container/flex';
  4. import ErrorBoundary from 'sentry/components/errorBoundary';
  5. import {DatePageFilter} from 'sentry/components/organizations/datePageFilter';
  6. import {EnvironmentPageFilter} from 'sentry/components/organizations/environmentPageFilter';
  7. import {t} from 'sentry/locale';
  8. import {space} from 'sentry/styles/space';
  9. import type {Event} from 'sentry/types/event';
  10. import type {Group} from 'sentry/types/group';
  11. import type {Project} from 'sentry/types/project';
  12. import {getConfigForIssueType} from 'sentry/utils/issueTypeConfig';
  13. import {useLocation} from 'sentry/utils/useLocation';
  14. import {useNavigate} from 'sentry/utils/useNavigate';
  15. import {EventGraph} from 'sentry/views/issueDetails/streamline/eventGraph';
  16. import {
  17. EventSearch,
  18. useEventQuery,
  19. } from 'sentry/views/issueDetails/streamline/eventSearch';
  20. import {ToggleSidebar} from 'sentry/views/issueDetails/streamline/toggleSidebar';
  21. import {Tab, TabPaths} from 'sentry/views/issueDetails/types';
  22. import {useGroupDetailsRoute} from 'sentry/views/issueDetails/useGroupDetailsRoute';
  23. import {useEnvironmentsFromUrl} from 'sentry/views/issueDetails/utils';
  24. export function EventDetailsHeader({
  25. group,
  26. event,
  27. project,
  28. }: {
  29. event: Event | undefined;
  30. group: Group;
  31. project: Project;
  32. }) {
  33. const navigate = useNavigate();
  34. const location = useLocation();
  35. const environments = useEnvironmentsFromUrl();
  36. const searchQuery = useEventQuery({group});
  37. const {baseUrl} = useGroupDetailsRoute();
  38. const issueTypeConfig = getConfigForIssueType(group, project);
  39. if (!issueTypeConfig.filterAndSearchHeader.enabled) {
  40. return null;
  41. }
  42. return (
  43. <PageErrorBoundary mini message={t('There was an error loading the event filters')}>
  44. <FilterContainer role="group" aria-description={t('Event filtering controls')}>
  45. <EnvironmentFilter
  46. triggerProps={{
  47. borderless: true,
  48. style: {
  49. borderRadius: 0,
  50. },
  51. }}
  52. />
  53. <DateFilter
  54. triggerProps={{
  55. borderless: true,
  56. style: {
  57. borderRadius: 0,
  58. },
  59. }}
  60. />
  61. <Flex style={{gridArea: 'search'}}>
  62. <SearchFilter
  63. group={group}
  64. handleSearch={query => {
  65. navigate({...location, query: {...location.query, query}}, {replace: true});
  66. }}
  67. environments={environments}
  68. query={searchQuery}
  69. queryBuilderProps={{
  70. disallowFreeText: true,
  71. }}
  72. />
  73. <ToggleSidebar />
  74. </Flex>
  75. <GraphSection>
  76. <EventGraph event={event} group={group} style={{flex: 1}} />
  77. <SectionDivider />
  78. <IssueTagsButton
  79. aria-label={t('View issue tag distributions')}
  80. to={{
  81. pathname: `${baseUrl}${TabPaths[Tab.TAGS]}`,
  82. query: location.query,
  83. replace: true,
  84. }}
  85. analyticsEventKey="issue_details.issue_tags_clicked"
  86. analyticsEventName="Issue Details: Issue Tags Clicked"
  87. >
  88. {t('Issue Tags')}
  89. </IssueTagsButton>
  90. </GraphSection>
  91. </FilterContainer>
  92. </PageErrorBoundary>
  93. );
  94. }
  95. const FilterContainer = styled('div')`
  96. padding-left: 24px;
  97. display: grid;
  98. grid-template-columns: auto auto minmax(100px, 1fr);
  99. grid-template-rows: minmax(38px, auto) auto;
  100. grid-template-areas:
  101. 'env date search toggle'
  102. 'graph graph graph graph';
  103. border: 0px solid ${p => p.theme.translucentBorder};
  104. border-width: 0 1px 1px 0;
  105. `;
  106. const EnvironmentFilter = styled(EnvironmentPageFilter)`
  107. grid-area: env;
  108. &:before {
  109. right: 0;
  110. top: ${space(1)};
  111. bottom: ${space(1)};
  112. width: 1px;
  113. content: '';
  114. position: absolute;
  115. background: ${p => p.theme.translucentInnerBorder};
  116. }
  117. `;
  118. const SearchFilter = styled(EventSearch)`
  119. border-color: transparent;
  120. border-radius: 0;
  121. box-shadow: none;
  122. `;
  123. const DateFilter = styled(DatePageFilter)`
  124. grid-area: date;
  125. &:before {
  126. right: 0;
  127. top: ${space(1)};
  128. bottom: ${space(1)};
  129. width: 1px;
  130. content: '';
  131. position: absolute;
  132. background: ${p => p.theme.translucentInnerBorder};
  133. }
  134. `;
  135. const GraphSection = styled('div')`
  136. grid-area: graph;
  137. display: flex;
  138. border-top: 1px solid ${p => p.theme.translucentBorder};
  139. `;
  140. const IssueTagsButton = styled(LinkButton)`
  141. display: block;
  142. flex: 0;
  143. height: unset;
  144. margin: ${space(1)} ${space(2)} ${space(1)} ${space(1)};
  145. padding: ${space(1)} ${space(1.5)};
  146. text-align: center;
  147. span {
  148. white-space: unset;
  149. }
  150. `;
  151. const SectionDivider = styled('div')`
  152. border-left: 1px solid ${p => p.theme.translucentBorder};
  153. display: flex;
  154. align-items: center;
  155. margin: ${space(1)};
  156. `;
  157. const PageErrorBoundary = styled(ErrorBoundary)`
  158. margin: 0;
  159. border: 0px solid ${p => p.theme.translucentBorder};
  160. border-width: 0 1px 1px 0;
  161. border-radius: 0;
  162. padding: ${space(1.5)} 24px;
  163. `;