styles.tsx 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. import {useState} from 'react';
  2. import styled from '@emotion/styled';
  3. import type {Location} from 'history';
  4. import EventTagsPill from 'sentry/components/events/eventTags/eventTagsPill';
  5. import {SecondaryHeader} from 'sentry/components/events/interfaces/spans/header';
  6. import Panel from 'sentry/components/panels/panel';
  7. import Pills from 'sentry/components/pills';
  8. import SearchBar from 'sentry/components/searchBar';
  9. import {t} from 'sentry/locale';
  10. import {space} from 'sentry/styles/space';
  11. import type {EventTag} from 'sentry/types/event';
  12. import type {Organization} from 'sentry/types/organization';
  13. import {defined, generateQueryWithTag} from 'sentry/utils';
  14. import type {
  15. TraceError,
  16. TraceFullDetailed,
  17. } from 'sentry/utils/performance/quickTrace/types';
  18. import {isTraceTransaction} from 'sentry/utils/performance/quickTrace/utils';
  19. import {appendTagCondition} from 'sentry/utils/queryString';
  20. import {transactionSummaryRouteWithQuery} from 'sentry/views/performance/transactionSummary/utils';
  21. export {
  22. Row,
  23. SpanDetails as TransactionDetails,
  24. SpanDetailContainer as TransactionDetailsContainer,
  25. } from 'sentry/components/events/interfaces/spans/spanDetail';
  26. export const TraceSearchContainer = styled('div')`
  27. display: flex;
  28. width: 100%;
  29. `;
  30. export const TraceSearchBar = styled(SearchBar)`
  31. flex-grow: 1;
  32. `;
  33. export const TraceViewHeaderContainer = styled(SecondaryHeader)`
  34. border-top: none;
  35. border-bottom: 1px solid ${p => p.theme.border};
  36. position: sticky;
  37. top: 0;
  38. z-index: 1;
  39. `;
  40. export const TraceDetailHeader = styled('div')`
  41. display: grid;
  42. grid-template-columns: 1fr;
  43. gap: ${space(3)};
  44. margin-bottom: ${space(2)};
  45. @media (min-width: ${p => p.theme.breakpoints.medium}) {
  46. grid-template-columns: max-content max-content;
  47. grid-row-gap: 0;
  48. }
  49. `;
  50. export const TraceDetailBody = styled('div')`
  51. height: 100%;
  52. `;
  53. export const TraceViewContainer = styled('div')`
  54. overflow-x: hidden;
  55. border-bottom-left-radius: 3px;
  56. border-bottom-right-radius: 3px;
  57. `;
  58. export const TracePanel = styled(Panel)`
  59. height: 100%;
  60. overflow: auto;
  61. `;
  62. export const ProjectBadgeContainer = styled('span')`
  63. margin-right: ${space(0.75)};
  64. display: flex;
  65. flex-direction: column;
  66. justify-content: center;
  67. `;
  68. const StyledPills = styled(Pills)`
  69. padding-top: ${space(1.5)};
  70. `;
  71. export function Tags({
  72. location,
  73. organization,
  74. enableHiding,
  75. event,
  76. tags,
  77. }: {
  78. event: TraceFullDetailed | TraceError;
  79. location: Location;
  80. organization: Organization;
  81. tags: EventTag[];
  82. enableHiding?: boolean;
  83. }) {
  84. const [showingAll, setShowingAll] = useState(enableHiding ? false : true);
  85. if (!tags || tags.length <= 0) {
  86. return null;
  87. }
  88. const orgSlug = organization.slug;
  89. const renderText = showingAll ? t('Show less') : t('Show more') + '...';
  90. return (
  91. <tr>
  92. <td className="key">Tags</td>
  93. <td className="value">
  94. <StyledPills>
  95. {tags.slice(0, showingAll ? tags.length : 5).map((tag, index) => {
  96. let streamPath = '';
  97. let query = {};
  98. if (isTraceTransaction(event)) {
  99. const route = transactionSummaryRouteWithQuery({
  100. orgSlug,
  101. transaction: event.transaction,
  102. projectID: String(event.project_id),
  103. query: {
  104. ...location.query,
  105. query: appendTagCondition(location.query.query, tag.key, tag.value),
  106. },
  107. });
  108. streamPath = route.pathname;
  109. query = route.query;
  110. } else {
  111. streamPath = `/organizations/${organization.slug}/issues/`;
  112. query = generateQueryWithTag(
  113. {...location.query, referrer: 'event-tags'},
  114. tag
  115. );
  116. }
  117. return (
  118. <EventTagsPill
  119. key={!defined(tag.key) ? `tag-pill-${index}` : tag.key}
  120. tag={tag}
  121. projectSlug={event.project_slug}
  122. projectId={event.project_id.toString()}
  123. organization={organization}
  124. query={query}
  125. streamPath={streamPath}
  126. />
  127. );
  128. })}
  129. {tags.length > 5 && enableHiding && (
  130. <div style={{position: 'relative', height: '20px'}}>
  131. <a
  132. style={{position: 'absolute', bottom: '0px', whiteSpace: 'nowrap'}}
  133. onClick={() => setShowingAll(prev => !prev)}
  134. >
  135. {renderText}
  136. </a>
  137. </div>
  138. )}
  139. </StyledPills>
  140. </td>
  141. </tr>
  142. );
  143. }