eventDetailsHeader.tsx 5.4 KB

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